Browse Source

Allow viewing 'typed IL'.

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
c2ac889ebe
  1. 5
      ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
  2. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 440
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 5
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  5. 28
      ICSharpCode.Decompiler/IL/ILVariable.cs
  6. 34
      ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
  7. 21
      ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs
  8. 12
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  9. 15
      ICSharpCode.Decompiler/IL/Instructions/BranchInstruction.cs
  10. 25
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  11. 4
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  12. 96
      ICSharpCode.Decompiler/IL/Instructions/OpCode.cs
  13. 14
      ICSharpCode.Decompiler/IL/Instructions/Prefix.cs
  14. 42
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  15. 37
      ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
  16. 25
      ICSharpCode.Decompiler/IL/Instructions/VarInstructions.cs
  17. 4
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  18. 1
      ICSharpCode.Decompiler/Tests/packages.config
  19. 2
      ICSharpCode.Decompiler/Util/Interval.cs
  20. 5
      ILSpy/App.xaml.cs
  21. 6
      ILSpy/ILSpy.csproj
  22. 71
      ILSpy/Languages/ILAstLanguage.cs
  23. 9
      ILSpy/Languages/ILLanguage.cs
  24. 3
      ILSpy/Languages/Languages.cs
  25. 2
      ILSpy/Properties/app.config.template
  26. 39
      ILSpy/TextView/DecompilerTextView.cs
  27. 1
      ILSpy/packages.config
  28. 77
      Mono.Cecil/Mono.Cecil.Cil/MethodBody.cs

5
ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs

@ -373,6 +373,11 @@ namespace ICSharpCode.Decompiler.Disassembler
} }
} }
public static void WriteOperand(ITextOutput writer, long val)
{
writer.Write(ToInvariantCultureString(val));
}
public static void WriteOperand(ITextOutput writer, float val) public static void WriteOperand(ITextOutput writer, float val)
{ {
if (val == 0) { if (val == 0) {

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -78,7 +78,9 @@
<Compile Include="IL\ILReader.cs" /> <Compile Include="IL\ILReader.cs" />
<Compile Include="IL\ILTypeExtensions.cs" /> <Compile Include="IL\ILTypeExtensions.cs" />
<Compile Include="IL\ILVariable.cs" /> <Compile Include="IL\ILVariable.cs" />
<Compile Include="IL\InstructionOutputExtensions.cs" />
<Compile Include="IL\Instructions\BinaryInstruction.cs" /> <Compile Include="IL\Instructions\BinaryInstruction.cs" />
<Compile Include="IL\Instructions\Block.cs" />
<Compile Include="IL\Instructions\BranchInstruction.cs" /> <Compile Include="IL\Instructions\BranchInstruction.cs" />
<Compile Include="IL\Instructions\CallInstruction.cs" /> <Compile Include="IL\Instructions\CallInstruction.cs" />
<Compile Include="IL\Instructions\ILInstruction.cs" /> <Compile Include="IL\Instructions\ILInstruction.cs" />

440
ICSharpCode.Decompiler/IL/ILReader.cs

@ -9,9 +9,9 @@ using Mono.Cecil;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
class ILReader(MethodDefinition method, private Mono.Cecil.Cil.MethodBody body) public class ILReader(private Mono.Cecil.Cil.MethodBody body)
{ {
public static ILOpCode ReadOpCode(ref BlobReader reader) internal static ILOpCode ReadOpCode(ref BlobReader reader)
{ {
byte b = reader.ReadByte(); byte b = reader.ReadByte();
if (b == 0xfe) if (b == 0xfe)
@ -20,7 +20,7 @@ namespace ICSharpCode.Decompiler.IL
return (ILOpCode)b; return (ILOpCode)b;
} }
public static MetadataToken ReadMetadataToken(ref BlobReader reader) internal static MetadataToken ReadMetadataToken(ref BlobReader reader)
{ {
return new MetadataToken(reader.ReadUInt32()); return new MetadataToken(reader.ReadUInt32());
} }
@ -28,6 +28,8 @@ namespace ICSharpCode.Decompiler.IL
ImmutableArray<ILInstruction>.Builder instructionBuilder = ImmutableArray.CreateBuilder<ILInstruction>(); ImmutableArray<ILInstruction>.Builder instructionBuilder = ImmutableArray.CreateBuilder<ILInstruction>();
BlobReader reader = body.GetILReader(); BlobReader reader = body.GetILReader();
Stack<StackType> stack = new Stack<StackType>(body.MaxStackSize); Stack<StackType> stack = new Stack<StackType>(body.MaxStackSize);
ILVariable[] parameterVariables;
ILVariable[] localVariables;
IMetadataTokenProvider ReadAndDecodeMetadataToken() IMetadataTokenProvider ReadAndDecodeMetadataToken()
{ {
@ -35,11 +37,13 @@ namespace ICSharpCode.Decompiler.IL
return body.LookupToken(token); return body.LookupToken(token);
} }
void ReadInstructions() public ImmutableArray<ILInstruction> ReadInstructions()
{ {
//var body = method.GetBody(); //var body = method.GetBody();
//var methodSignature = new MethodSignature(method.Signature); //var methodSignature = new MethodSignature(method.Signature);
//var localVariableTypes = GetStackTypes(body.GetLocalVariableTypes(method.ContainingModule.metadata)); //var localVariableTypes = GetStackTypes(body.GetLocalVariableTypes(method.ContainingModule.metadata));
localVariables = body.Variables.Select(v => new ILVariable(v)).ToArray();
parameterVariables = body.Method.Parameters.Select(p => new ILVariable(p)).ToArray();
//var parameterTypes = GetStackTypes(methodSignature.ParameterTypes); //var parameterTypes = GetStackTypes(methodSignature.ParameterTypes);
//var stack = new Stack<StackType>(body.MaxStack); //var stack = new Stack<StackType>(body.MaxStack);
@ -65,11 +69,12 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
} }
} return instructionBuilder.ToImmutable();
}
private bool IsUnconditionalBranch(OpCode opCode) private bool IsUnconditionalBranch(OpCode opCode)
{ {
return opCode == OpCode.Branch; return opCode == OpCode.Branch || opCode == OpCode.Ret || opCode == OpCode.Leave;
} }
ILInstruction DecodeInstruction() ILInstruction DecodeInstruction()
@ -78,8 +83,6 @@ namespace ICSharpCode.Decompiler.IL
switch (ilOpCode) { switch (ilOpCode) {
case ILOpCode.Constrained: case ILOpCode.Constrained:
return DecodeConstrainedCall(); return DecodeConstrainedCall();
case ILOpCode.Nop:
return DecodeNoPrefix();
case ILOpCode.Readonly: case ILOpCode.Readonly:
throw new NotImplementedException(); // needs ldelema throw new NotImplementedException(); // needs ldelema
case ILOpCode.Tailcall: case ILOpCode.Tailcall:
@ -89,13 +92,13 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Volatile: case ILOpCode.Volatile:
return DecodeVolatile(); return DecodeVolatile();
case ILOpCode.Add: case ILOpCode.Add:
return DecodeBinaryNumericInstruction(OpCode.Add); return BinaryNumeric(OpCode.Add);
case ILOpCode.Add_Ovf: case ILOpCode.Add_Ovf:
return DecodeBinaryNumericInstruction(OpCode.Add, OverflowMode.Ovf); return BinaryNumeric(OpCode.Add, OverflowMode.Ovf);
case ILOpCode.Add_Ovf_Un: case ILOpCode.Add_Ovf_Un:
return DecodeBinaryNumericInstruction(OpCode.Add, OverflowMode.Ovf_Un); return BinaryNumeric(OpCode.Add, OverflowMode.Ovf_Un);
case ILOpCode.And: case ILOpCode.And:
return DecodeBinaryNumericInstruction(OpCode.BitAnd); return BinaryNumeric(OpCode.BitAnd);
case ILOpCode.Arglist: case ILOpCode.Arglist:
stack.Push(StackType.O); stack.Push(StackType.O);
return new SimpleInstruction(OpCode.Arglist); return new SimpleInstruction(OpCode.Arglist);
@ -140,9 +143,9 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Bne_Un_S: case ILOpCode.Bne_Un_S:
return DecodeComparisonBranch(true, OpCode.Ceq, OpCode.Ceq, true); return DecodeComparisonBranch(true, OpCode.Ceq, OpCode.Ceq, true);
case ILOpCode.Br: case ILOpCode.Br:
return DecodeUnconditionalBranch(false); return DecodeUnconditionalBranch(false, OpCode.Branch);
case ILOpCode.Br_S: case ILOpCode.Br_S:
return DecodeUnconditionalBranch(true); return DecodeUnconditionalBranch(true, OpCode.Branch);
case ILOpCode.Break: case ILOpCode.Break:
return new SimpleInstruction(OpCode.Break); return new SimpleInstruction(OpCode.Break);
case ILOpCode.Brfalse: case ILOpCode.Brfalse:
@ -155,92 +158,94 @@ namespace ICSharpCode.Decompiler.IL
return DecodeConditionalBranch(true, false); return DecodeConditionalBranch(true, false);
case ILOpCode.Call: case ILOpCode.Call:
return DecodeCall(OpCode.Call); return DecodeCall(OpCode.Call);
case ILOpCode.Callvirt:
return DecodeCall(OpCode.CallVirt);
case ILOpCode.Calli: case ILOpCode.Calli:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Ceq: case ILOpCode.Ceq:
return DecodeComparison(OpCode.Ceq, OpCode.Ceq); return Comparison(OpCode.Ceq, OpCode.Ceq);
case ILOpCode.Cgt: case ILOpCode.Cgt:
return DecodeComparison(OpCode.Cgt, OpCode.Cgt); return Comparison(OpCode.Cgt, OpCode.Cgt);
case ILOpCode.Cgt_Un: case ILOpCode.Cgt_Un:
return DecodeComparison(OpCode.Cgt_Un, OpCode.Cgt_Un); return Comparison(OpCode.Cgt_Un, OpCode.Cgt_Un);
case ILOpCode.Clt: case ILOpCode.Clt:
return DecodeComparison(OpCode.Clt, OpCode.Clt); return Comparison(OpCode.Clt, OpCode.Clt);
case ILOpCode.Clt_Un: case ILOpCode.Clt_Un:
return DecodeComparison(OpCode.Clt_Un, OpCode.Clt_Un); return Comparison(OpCode.Clt_Un, OpCode.Clt_Un);
case ILOpCode.Ckfinite: case ILOpCode.Ckfinite:
return new PeekInstruction(OpCode.Ckfinite); return new PeekInstruction(OpCode.Ckfinite);
case ILOpCode.Conv_I1: case ILOpCode.Conv_I1:
return DecodeConv(PrimitiveType.I1, OverflowMode.None); return Conv(PrimitiveType.I1, OverflowMode.None);
case ILOpCode.Conv_I2: case ILOpCode.Conv_I2:
return DecodeConv(PrimitiveType.I2, OverflowMode.None); return Conv(PrimitiveType.I2, OverflowMode.None);
case ILOpCode.Conv_I4: case ILOpCode.Conv_I4:
return DecodeConv(PrimitiveType.I4, OverflowMode.None); return Conv(PrimitiveType.I4, OverflowMode.None);
case ILOpCode.Conv_I8: case ILOpCode.Conv_I8:
return DecodeConv(PrimitiveType.I8, OverflowMode.None); return Conv(PrimitiveType.I8, OverflowMode.None);
case ILOpCode.Conv_R4: case ILOpCode.Conv_R4:
return DecodeConv(PrimitiveType.R4, OverflowMode.None); return Conv(PrimitiveType.R4, OverflowMode.None);
case ILOpCode.Conv_R8: case ILOpCode.Conv_R8:
return DecodeConv(PrimitiveType.R8, OverflowMode.None); return Conv(PrimitiveType.R8, OverflowMode.None);
case ILOpCode.Conv_U1: case ILOpCode.Conv_U1:
return DecodeConv(PrimitiveType.U1, OverflowMode.None); return Conv(PrimitiveType.U1, OverflowMode.None);
case ILOpCode.Conv_U2: case ILOpCode.Conv_U2:
return DecodeConv(PrimitiveType.U2, OverflowMode.None); return Conv(PrimitiveType.U2, OverflowMode.None);
case ILOpCode.Conv_U4: case ILOpCode.Conv_U4:
return DecodeConv(PrimitiveType.U4, OverflowMode.None); return Conv(PrimitiveType.U4, OverflowMode.None);
case ILOpCode.Conv_U8: case ILOpCode.Conv_U8:
return DecodeConv(PrimitiveType.U8, OverflowMode.None); return Conv(PrimitiveType.U8, OverflowMode.None);
case ILOpCode.Conv_I: case ILOpCode.Conv_I:
return DecodeConv(PrimitiveType.I, OverflowMode.None); return Conv(PrimitiveType.I, OverflowMode.None);
case ILOpCode.Conv_U: case ILOpCode.Conv_U:
return DecodeConv(PrimitiveType.U, OverflowMode.None); return Conv(PrimitiveType.U, OverflowMode.None);
case ILOpCode.Conv_R_Un: case ILOpCode.Conv_R_Un:
return DecodeConv(PrimitiveType.R8, OverflowMode.Un); return Conv(PrimitiveType.R8, OverflowMode.Un);
case ILOpCode.Conv_Ovf_I1: case ILOpCode.Conv_Ovf_I1:
return DecodeConv(PrimitiveType.I1, OverflowMode.Ovf); return Conv(PrimitiveType.I1, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_I2: case ILOpCode.Conv_Ovf_I2:
return DecodeConv(PrimitiveType.I2, OverflowMode.Ovf); return Conv(PrimitiveType.I2, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_I4: case ILOpCode.Conv_Ovf_I4:
return DecodeConv(PrimitiveType.I4, OverflowMode.Ovf); return Conv(PrimitiveType.I4, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_I8: case ILOpCode.Conv_Ovf_I8:
return DecodeConv(PrimitiveType.I8, OverflowMode.Ovf); return Conv(PrimitiveType.I8, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_U1: case ILOpCode.Conv_Ovf_U1:
return DecodeConv(PrimitiveType.U1, OverflowMode.Ovf); return Conv(PrimitiveType.U1, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_U2: case ILOpCode.Conv_Ovf_U2:
return DecodeConv(PrimitiveType.U2, OverflowMode.Ovf); return Conv(PrimitiveType.U2, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_U4: case ILOpCode.Conv_Ovf_U4:
return DecodeConv(PrimitiveType.U4, OverflowMode.Ovf); return Conv(PrimitiveType.U4, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_U8: case ILOpCode.Conv_Ovf_U8:
return DecodeConv(PrimitiveType.U8, OverflowMode.Ovf); return Conv(PrimitiveType.U8, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_I: case ILOpCode.Conv_Ovf_I:
return DecodeConv(PrimitiveType.I, OverflowMode.Ovf); return Conv(PrimitiveType.I, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_U: case ILOpCode.Conv_Ovf_U:
return DecodeConv(PrimitiveType.U, OverflowMode.Ovf); return Conv(PrimitiveType.U, OverflowMode.Ovf);
case ILOpCode.Conv_Ovf_I1_Un: case ILOpCode.Conv_Ovf_I1_Un:
return DecodeConv(PrimitiveType.I1, OverflowMode.Ovf_Un); return Conv(PrimitiveType.I1, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_I2_Un: case ILOpCode.Conv_Ovf_I2_Un:
return DecodeConv(PrimitiveType.I2, OverflowMode.Ovf_Un); return Conv(PrimitiveType.I2, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_I4_Un: case ILOpCode.Conv_Ovf_I4_Un:
return DecodeConv(PrimitiveType.I4, OverflowMode.Ovf_Un); return Conv(PrimitiveType.I4, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_I8_Un: case ILOpCode.Conv_Ovf_I8_Un:
return DecodeConv(PrimitiveType.I8, OverflowMode.Ovf_Un); return Conv(PrimitiveType.I8, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_U1_Un: case ILOpCode.Conv_Ovf_U1_Un:
return DecodeConv(PrimitiveType.U1, OverflowMode.Ovf_Un); return Conv(PrimitiveType.U1, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_U2_Un: case ILOpCode.Conv_Ovf_U2_Un:
return DecodeConv(PrimitiveType.U2, OverflowMode.Ovf_Un); return Conv(PrimitiveType.U2, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_U4_Un: case ILOpCode.Conv_Ovf_U4_Un:
return DecodeConv(PrimitiveType.U4, OverflowMode.Ovf_Un); return Conv(PrimitiveType.U4, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_U8_Un: case ILOpCode.Conv_Ovf_U8_Un:
return DecodeConv(PrimitiveType.U8, OverflowMode.Ovf_Un); return Conv(PrimitiveType.U8, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_I_Un: case ILOpCode.Conv_Ovf_I_Un:
return DecodeConv(PrimitiveType.I, OverflowMode.Ovf_Un); return Conv(PrimitiveType.I, OverflowMode.Ovf_Un);
case ILOpCode.Conv_Ovf_U_Un: case ILOpCode.Conv_Ovf_U_Un:
return DecodeConv(PrimitiveType.U, OverflowMode.Ovf_Un); return Conv(PrimitiveType.U, OverflowMode.Ovf_Un);
case ILOpCode.Cpblk: case ILOpCode.Cpblk:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Div: case ILOpCode.Div:
return DecodeBinaryNumericInstruction(OpCode.Div, OverflowMode.None); return BinaryNumeric(OpCode.Div, OverflowMode.None);
case ILOpCode.Div_Un: case ILOpCode.Div_Un:
return DecodeBinaryNumericInstruction(OpCode.Div, OverflowMode.Un); return BinaryNumeric(OpCode.Div, OverflowMode.Un);
case ILOpCode.Dup: case ILOpCode.Dup:
return new PeekInstruction(OpCode.Peek); return new PeekInstruction(OpCode.Peek);
case ILOpCode.Endfilter: case ILOpCode.Endfilter:
@ -251,11 +256,293 @@ namespace ICSharpCode.Decompiler.IL
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Jmp: case ILOpCode.Jmp:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Ldarg:
return Ldarg(reader.ReadUInt16());
case ILOpCode.Ldarg_S:
return Ldarg(reader.ReadByte());
case ILOpCode.Ldarg_0:
case ILOpCode.Ldarg_1:
case ILOpCode.Ldarg_2:
case ILOpCode.Ldarg_3:
return Ldarg(ilOpCode - ILOpCode.Ldarg_0);
case ILOpCode.Ldarga:
return Ldarga(reader.ReadUInt16());
case ILOpCode.Ldarga_S:
return Ldarga(reader.ReadByte());
case ILOpCode.Ldc_I4:
return LdcI4(reader.ReadInt32());
case ILOpCode.Ldc_I8:
return LdcI8(reader.ReadInt64());
case ILOpCode.Ldc_R4:
return LdcF(reader.ReadSingle());
case ILOpCode.Ldc_R8:
return LdcF(reader.ReadDouble());
case ILOpCode.Ldc_I4_M1:
case ILOpCode.Ldc_I4_0:
case ILOpCode.Ldc_I4_1:
case ILOpCode.Ldc_I4_2:
case ILOpCode.Ldc_I4_3:
case ILOpCode.Ldc_I4_4:
case ILOpCode.Ldc_I4_5:
case ILOpCode.Ldc_I4_6:
case ILOpCode.Ldc_I4_7:
case ILOpCode.Ldc_I4_8:
return LdcI4(ilOpCode - ILOpCode.Ldc_I4_0);
case ILOpCode.Ldc_I4_S:
return LdcI4(reader.ReadSByte());
case ILOpCode.Ldnull:
stack.Push(StackType.O);
return new SimpleInstruction(OpCode.LdNull);
case ILOpCode.Ldstr:
return DecodeLdstr();
case ILOpCode.Ldftn:
throw new NotImplementedException();
case ILOpCode.Ldind_I1:
case ILOpCode.Ldind_I2:
case ILOpCode.Ldind_I4:
case ILOpCode.Ldind_I8:
case ILOpCode.Ldind_U1:
case ILOpCode.Ldind_U2:
case ILOpCode.Ldind_U4:
case ILOpCode.Ldind_R4:
case ILOpCode.Ldind_R8:
case ILOpCode.Ldind_I:
case ILOpCode.Ldind_Ref:
throw new NotImplementedException();
case ILOpCode.Ldloc:
return Ldloc(reader.ReadUInt16());
case ILOpCode.Ldloc_S:
return Ldloc(reader.ReadByte());
case ILOpCode.Ldloc_0:
case ILOpCode.Ldloc_1:
case ILOpCode.Ldloc_2:
case ILOpCode.Ldloc_3:
return Ldloc(ilOpCode - ILOpCode.Ldloc_0);
case ILOpCode.Ldloca:
return Ldloca(reader.ReadUInt16());
case ILOpCode.Ldloca_S:
return Ldloca(reader.ReadByte());
case ILOpCode.Leave:
return DecodeUnconditionalBranch(false, OpCode.Leave);
case ILOpCode.Leave_S:
return DecodeUnconditionalBranch(true, OpCode.Leave);
case ILOpCode.Localloc:
throw new NotImplementedException();
case ILOpCode.Mul:
return BinaryNumeric(OpCode.Mul, OverflowMode.None);
case ILOpCode.Mul_Ovf:
return BinaryNumeric(OpCode.Mul, OverflowMode.Ovf);
case ILOpCode.Mul_Ovf_Un:
return BinaryNumeric(OpCode.Mul, OverflowMode.Ovf_Un);
case ILOpCode.Neg:
return UnaryNumeric(OpCode.Neg);
case ILOpCode.Nop:
return new SimpleInstruction(OpCode.Nop);
case ILOpCode.Not:
return UnaryNumeric(OpCode.BitNot);
case ILOpCode.Or:
return BinaryNumeric(OpCode.BitOr);
case ILOpCode.Pop:
stack.PopOrDefault();
return new UnaryInstruction(OpCode.Void);
case ILOpCode.Rem:
return BinaryNumeric(OpCode.Rem, OverflowMode.None);
case ILOpCode.Rem_Un:
return BinaryNumeric(OpCode.Rem, OverflowMode.Un);
case ILOpCode.Ret:
return Ret();
case ILOpCode.Shl:
return Shift(OpCode.Shl);
case ILOpCode.Shr:
return Shift(OpCode.Shr);
case ILOpCode.Shr_Un:
return Shift(OpCode.Shl, OverflowMode.Un);
case ILOpCode.Starg:
return Starg(reader.ReadUInt16());
case ILOpCode.Starg_S:
return Starg(reader.ReadByte());
case ILOpCode.Stind_I1:
case ILOpCode.Stind_I2:
case ILOpCode.Stind_I4:
case ILOpCode.Stind_I8:
case ILOpCode.Stind_R4:
case ILOpCode.Stind_R8:
case ILOpCode.Stind_I:
case ILOpCode.Stind_Ref:
throw new NotImplementedException();
case ILOpCode.Stloc:
return Stloc(reader.ReadUInt16());
case ILOpCode.Stloc_S:
return Stloc(reader.ReadByte());
case ILOpCode.Stloc_0:
case ILOpCode.Stloc_1:
case ILOpCode.Stloc_2:
case ILOpCode.Stloc_3:
return Stloc(ilOpCode - ILOpCode.Stloc_0);
case ILOpCode.Box:
throw new NotImplementedException();
case ILOpCode.Castclass:
throw new NotImplementedException();
case ILOpCode.Cpobj:
throw new NotImplementedException();
case ILOpCode.Initobj:
throw new NotImplementedException();
case ILOpCode.Isinst:
throw new NotImplementedException();
case ILOpCode.Ldelem:
case ILOpCode.Ldelem_I1:
case ILOpCode.Ldelem_I2:
case ILOpCode.Ldelem_I4:
case ILOpCode.Ldelem_I8:
case ILOpCode.Ldelem_U1:
case ILOpCode.Ldelem_U2:
case ILOpCode.Ldelem_U4:
case ILOpCode.Ldelem_R4:
case ILOpCode.Ldelem_R8:
case ILOpCode.Ldelem_I:
case ILOpCode.Ldelem_Ref:
throw new NotImplementedException();
case ILOpCode.Ldelema:
throw new NotImplementedException();
case ILOpCode.Ldfld:
throw new NotImplementedException();
case ILOpCode.Ldflda:
throw new NotImplementedException();
case ILOpCode.Stfld:
throw new NotImplementedException();
case ILOpCode.Ldlen:
throw new NotImplementedException();
case ILOpCode.Ldobj:
throw new NotImplementedException();
case ILOpCode.Ldsfld:
throw new NotImplementedException();
case ILOpCode.Ldsflda:
throw new NotImplementedException();
case ILOpCode.Stsfld:
throw new NotImplementedException();
case ILOpCode.Ldtoken:
throw new NotImplementedException();
case ILOpCode.Ldvirtftn:
throw new NotImplementedException();
case ILOpCode.Mkrefany:
throw new NotImplementedException();
case ILOpCode.Newarr:
throw new NotImplementedException();
case ILOpCode.Refanytype:
throw new NotImplementedException();
case ILOpCode.Refanyval:
throw new NotImplementedException();
case ILOpCode.Rethrow:
throw new NotImplementedException();
case ILOpCode.Sizeof:
throw new NotImplementedException();
case ILOpCode.Stelem:
case ILOpCode.Stelem_I1:
case ILOpCode.Stelem_I2:
case ILOpCode.Stelem_I4:
case ILOpCode.Stelem_I8:
case ILOpCode.Stelem_R4:
case ILOpCode.Stelem_R8:
case ILOpCode.Stelem_I:
case ILOpCode.Stelem_Ref:
throw new NotImplementedException();
case ILOpCode.Stobj:
throw new NotImplementedException();
case ILOpCode.Throw:
throw new NotImplementedException();
case ILOpCode.Unbox:
case ILOpCode.Unbox_Any:
throw new NotImplementedException();
default: default:
return InvalidInstruction(); throw new NotImplementedException(ilOpCode.ToString());
} }
} }
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 Ret()
{
if (body.Method.ReturnType.GetStackType() == StackType.Void)
return new SimpleInstruction(OpCode.Ret);
else
return new UnaryInstruction(OpCode.Ret);
}
private ILInstruction UnaryNumeric(OpCode opCode)
{
var opType = stack.PopOrDefault();
stack.Push(opType);
return new UnaryNumericInstruction(opCode, opType);
}
private ILInstruction DecodeLdstr()
{
stack.Push(StackType.O);
var metadataToken = ReadMetadataToken(ref reader);
return new ConstantStringInstruction(body.LookupStringToken(metadataToken));
}
private ILInstruction LdcI4(int val)
{
stack.Push(StackType.I4);
return new ConstantI4Instruction(val);
}
private ILInstruction LdcI8(long val)
{
stack.Push(StackType.I8);
return new ConstantI8Instruction(val);
}
private ILInstruction LdcF(double val)
{
stack.Push(StackType.F);
return new ConstantFloatInstruction(val);
}
private ILInstruction Ldarg(ushort v)
{
stack.Push(parameterVariables[v].Type.GetStackType());
return new LoadVarInstruction(parameterVariables[v]);
}
private ILInstruction Ldarga(ushort v)
{
stack.Push(StackType.Ref);
return new LoadVarInstruction(parameterVariables[v], OpCode.LoadVarAddress);
}
private ILInstruction Starg(ushort v)
{
stack.PopOrDefault();
return new StoreVarInstruction(parameterVariables[v]);
}
private ILInstruction Ldloc(ushort v)
{
stack.Push(localVariables[v].Type.GetStackType());
return new LoadVarInstruction(localVariables[v]);
}
private ILInstruction Ldloca(ushort v)
{
stack.Push(StackType.Ref);
return new LoadVarInstruction(localVariables[v], OpCode.LoadVarAddress);
}
private ILInstruction Stloc(ushort v)
{
stack.PopOrDefault();
return new StoreVarInstruction(localVariables[v]);
}
private ILInstruction DecodeConstrainedCall() private ILInstruction DecodeConstrainedCall()
{ {
var typeRef = ReadAndDecodeMetadataToken() as TypeReference; var typeRef = ReadAndDecodeMetadataToken() as TypeReference;
@ -290,31 +577,26 @@ namespace ICSharpCode.Decompiler.IL
return inst; return inst;
} }
/// <summary>no prefix -- possibly skip a fault check</summary> private ILInstruction Conv(PrimitiveType targetType, OverflowMode mode)
private ILInstruction DecodeNoPrefix()
{
var flags = (NoPrefixFlags)reader.ReadByte();
var inst = DecodeInstruction();
if ((var snp = inst as ISupportsNoPrefix) != null)
snp.NoPrefix = flags;
return inst;
}
private ILInstruction DecodeConv(PrimitiveType targetType, OverflowMode mode)
{ {
StackType from = stack.PopOrDefault(); StackType from = stack.PopOrDefault();
return new ConvInstruction(from, targetType, mode); return new ConvInstruction(from, targetType, mode);
} }
ILInstruction DecodeCall(OpCode call) ILInstruction DecodeCall(OpCode opCode)
{ {
var token = ReadMetadataToken(ref reader); var method = (MethodReference)ReadAndDecodeMetadataToken();
var methodRef = body.LookupToken(token); int numPopCalls = Math.Min(stack.Count, method.GetPopAmount());
// TODO: we need the decoded + (in case of generic calls) type substituted for (int i = 0; i < numPopCalls; i++) {
throw new NotImplementedException(); stack.Pop();
}
var returnType = method.ReturnType.GetStackType();
if (returnType != StackType.Void)
stack.Push(returnType);
return new CallInstruction(opCode, method);
} }
ILInstruction DecodeComparison(OpCode opCode_I, OpCode opCode_F) ILInstruction Comparison(OpCode opCode_I, OpCode opCode_F)
{ {
StackType right = stack.PopOrDefault(); StackType right = stack.PopOrDefault();
StackType left = stack.PopOrDefault(); StackType left = stack.PopOrDefault();
@ -331,7 +613,7 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction DecodeComparisonBranch(bool shortForm, OpCode comparisonOpCodeForInts, OpCode comparisonOpCodeForFloats, bool negate) ILInstruction DecodeComparisonBranch(bool shortForm, OpCode comparisonOpCodeForInts, OpCode comparisonOpCodeForFloats, bool negate)
{ {
int start = reader.Position - 1; int start = reader.Position - 1;
var condition = DecodeComparison(comparisonOpCodeForInts, comparisonOpCodeForFloats); var condition = Comparison(comparisonOpCodeForInts, comparisonOpCodeForFloats);
int target = start + (shortForm ? reader.ReadSByte() : reader.ReadInt32()); int target = start + (shortForm ? reader.ReadSByte() : reader.ReadInt32());
condition.ILRange = new Interval(start, reader.Position); condition.ILRange = new Interval(start, reader.Position);
if (negate) { if (negate) {
@ -351,14 +633,14 @@ namespace ICSharpCode.Decompiler.IL
return new ConditionalBranchInstruction(condition, target); return new ConditionalBranchInstruction(condition, target);
} }
ILInstruction DecodeUnconditionalBranch(bool shortForm) ILInstruction DecodeUnconditionalBranch(bool shortForm, OpCode opCode)
{ {
int start = reader.Position - 1; int start = reader.Position - 1;
int target = start + (shortForm ? reader.ReadSByte() : reader.ReadInt32()); int target = start + (shortForm ? reader.ReadSByte() : reader.ReadInt32());
return new BranchInstruction(OpCode.Branch, target); return new BranchInstruction(opCode, target);
} }
ILInstruction DecodeBinaryNumericInstruction(OpCode opCode, OverflowMode overflowMode = OverflowMode.None) ILInstruction BinaryNumeric(OpCode opCode, OverflowMode overflowMode = OverflowMode.None)
{ {
StackType right = stack.PopOrDefault(); StackType right = stack.PopOrDefault();
StackType left = stack.PopOrDefault(); StackType left = stack.PopOrDefault();
@ -386,11 +668,5 @@ namespace ICSharpCode.Decompiler.IL
stack.Push(StackType.Unknown); stack.Push(StackType.Unknown);
return new BinaryNumericInstruction(opCode, StackType.Unknown, overflowMode); return new BinaryNumericInstruction(opCode, StackType.Unknown, overflowMode);
} }
ILInstruction InvalidInstruction()
{
Debug.Fail("This should only happen in obfuscated code");
return new SimpleInstruction(OpCode.Invalid);
}
} }
} }

5
ICSharpCode.Decompiler/IL/ILTypeExtensions.cs

@ -20,6 +20,11 @@ namespace ICSharpCode.Decompiler.IL
return ImmutableArray.Create(result); return ImmutableArray.Create(result);
}*/ }*/
public static int GetPopAmount(this MethodReference methodRef)
{
return methodRef.Parameters.Count + (methodRef.HasThis ? 1 : 0);
}
public static StackType GetStackType(this TypeReference typeRef) public static StackType GetStackType(this TypeReference typeRef)
{ {
return typeRef.SkipModifiers().MetadataType.GetStackType(); return typeRef.SkipModifiers().MetadataType.GetStackType();

28
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -1,4 +1,6 @@
using System; using Mono.Cecil;
using Mono.Cecil.Cil;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -12,8 +14,28 @@ namespace ICSharpCode.Decompiler.IL
Parameter, Parameter,
} }
class ILVariable(public readonly VariableKind Kind, public readonly int Index) class ILVariable(public readonly VariableKind Kind, public readonly TypeReference Type, public readonly int Index)
{ {
public ILVariable(VariableDefinition v)
: this(VariableKind.Local, v.VariableType, v.Index)
{
}
public ILVariable(ParameterDefinition p)
: this(VariableKind.Parameter, p.ParameterType, p.Index)
{
}
public override string ToString()
{
switch (Kind) {
case VariableKind.Local:
return "V_" + Index.ToString();
case VariableKind.Parameter:
return "P_" + Index.ToString();
default:
return Kind.ToString();
}
}
} }
} }

34
ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
static class InstructionOutputExtensions
{
public static void Write(this ITextOutput output, OpCode opCode)
{
output.Write(opCode.ToString().ToLowerInvariant());
}
public static void Write(this ITextOutput output, StackType stackType)
{
output.Write(stackType.ToString().ToLowerInvariant());
}
public static void Write(this ITextOutput output, PrimitiveType primitiveType)
{
output.Write(primitiveType.ToString().ToLowerInvariant());
}
public static void WriteSuffix(this ITextOutput output, OverflowMode mode)
{
if ((mode & OverflowMode.Ovf) != 0)
output.Write(".ovf");
if ((mode & OverflowMode.Un) != 0)
output.Write(".un");
}
}
}

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

@ -19,12 +19,33 @@ namespace ICSharpCode.Decompiler.IL
{ {
public readonly StackType OpType = opType; public readonly StackType OpType = opType;
public readonly OverflowMode OverflowMode = overflowMode; public readonly OverflowMode OverflowMode = overflowMode;
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.WriteSuffix(OverflowMode);
output.Write(' ');
output.Write(OpType);
Left.WriteTo(output);
output.Write(", ");
Right.WriteTo(output);
output.Write(')');
}
} }
class BinaryComparisonInstruction(OpCode opCode, StackType opType) class BinaryComparisonInstruction(OpCode opCode, StackType opType)
: BinaryInstruction(opCode) : BinaryInstruction(opCode)
{ {
public readonly StackType OpType = opType; public readonly StackType OpType = opType;
public override void WriteTo(ITextOutput output)
{
output.Write("{0}.{1}(", OpCode, OpType);
Left.WriteTo(output);
output.Write(", ");
Right.WriteTo(output);
output.Write(')');
}
} }
public enum OverflowMode : byte public enum OverflowMode : byte

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

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL.Instructions
{
class Block
{
}
}

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

@ -12,6 +12,13 @@ namespace ICSharpCode.Decompiler.IL
class BranchInstruction(OpCode opCode, public int TargetILOffset) : ILInstruction(opCode) class BranchInstruction(OpCode opCode, public int TargetILOffset) : ILInstruction(opCode)
{ {
public override bool IsPeeking { get { return false; } } public override bool IsPeeking { get { return false; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode.ToString());
output.Write(' ');
output.WriteReference(CecilExtensions.OffsetToString(TargetILOffset), TargetILOffset, isLocal: true);
}
} }
/// <summary> /// <summary>
@ -21,5 +28,13 @@ namespace ICSharpCode.Decompiler.IL
class ConditionalBranchInstruction(public ILInstruction Condition, int targetILOffset) : BranchInstruction(OpCode.ConditionalBranch, targetILOffset) class ConditionalBranchInstruction(public ILInstruction Condition, int targetILOffset) : BranchInstruction(OpCode.ConditionalBranch, targetILOffset)
{ {
public override bool IsPeeking { get { return Condition.IsPeeking; } } public override bool IsPeeking { get { return Condition.IsPeeking; } }
public override void WriteTo(ITextOutput output)
{
base.WriteTo(output);
output.Write('(');
Condition.WriteTo(output);
output.Write(')');
}
} }
} }

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

@ -1,4 +1,5 @@
using Mono.Cecil; using ICSharpCode.Decompiler.Disassembler;
using Mono.Cecil;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -14,7 +15,7 @@ namespace ICSharpCode.Decompiler.IL
static ILInstruction[] InitOperands(MethodReference mr) static ILInstruction[] InitOperands(MethodReference mr)
{ {
ILInstruction[] operands = new ILInstruction[mr.Parameters.Count]; ILInstruction[] operands = new ILInstruction[mr.GetPopAmount()];
for (int i = 0; i < operands.Length; i++) { for (int i = 0; i < operands.Length; i++) {
operands[i] = Pop; operands[i] = Pop;
} }
@ -33,5 +34,25 @@ namespace ICSharpCode.Decompiler.IL
/// Returns null if no 'constrained.' prefix exists for this call. /// Returns null if no 'constrained.' prefix exists for this call.
/// </summary> /// </summary>
public TypeReference ConstrainedTo; public TypeReference ConstrainedTo;
public override void WriteTo(ITextOutput output)
{
if (ConstrainedTo != null) {
output.Write("constrained.");
ConstrainedTo.WriteTo(output, ILNameSyntax.ShortTypeName);
}
if (IsTail)
output.Write("tail.");
output.Write(OpCode);
output.Write(' ');
Method.WriteTo(output);
output.Write('(');
for (int i = 0; i < Operands.Length; i++) {
if (i > 0)
output.Write(", ");
Operands[i].WriteTo(output);
}
output.Write(')');
}
} }
} }

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

@ -9,7 +9,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Represents a decoded IL instruction /// Represents a decoded IL instruction
/// </summary> /// </summary>
abstract class ILInstruction(public readonly OpCode OpCode) public abstract class ILInstruction(public readonly OpCode OpCode)
{ {
public static readonly ILInstruction Nop = new SimpleInstruction(OpCode.Nop); public static readonly ILInstruction Nop = new SimpleInstruction(OpCode.Nop);
public static readonly ILInstruction Pop = new SimpleInstruction(OpCode.Pop); public static readonly ILInstruction Pop = new SimpleInstruction(OpCode.Pop);
@ -25,5 +25,7 @@ namespace ICSharpCode.Decompiler.IL
/// left after the pop operations. /// left after the pop operations.
/// </summary> /// </summary>
public abstract bool IsPeeking { get; } public abstract bool IsPeeking { get; }
public abstract void WriteTo(ITextOutput output);
} }
} }

96
ICSharpCode.Decompiler/IL/Instructions/OpCode.cs

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
enum OpCode public enum OpCode
{ {
/// <summary> /// <summary>
/// A instruction that could not be decoded correctly. /// A instruction that could not be decoded correctly.
@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.IL
/// Ignore the arguments and produce void. Used to prevent the end result of an instruction /// Ignore the arguments and produce void. Used to prevent the end result of an instruction
/// from being pushed to the evaluation stack. /// from being pushed to the evaluation stack.
/// </summary> /// </summary>
Drop, Void,
/// <summary> /// <summary>
/// Unary operator that expects an input of type I4. /// Unary operator that expects an input of type I4.
/// Return 1 (of type I4) if the input value is 0. Otherwise, return 0 (of type I4). /// Return 1 (of type I4) if the input value is 0. Otherwise, return 0 (of type I4).
@ -43,10 +43,42 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
Add, Add,
/// <summary> /// <summary>
/// Subtracts two numbers. <see cref="BinaryNumericInstruction"/>
/// </summary>
Sub,
/// <summary>
/// Multiplies two numbers. <see cref="BinaryNumericInstruction"/>
/// </summary>
Mul,
/// <summary>
/// Division. <see cref="BinaryNumericInstruction"/>
/// </summary>
Div,
/// <summary>
/// Division remainder. <see cref="BinaryNumericInstruction"/>
/// </summary>
Rem,
/// <summary>
/// Unary negation. <see cref="UnaryInstruction"/>
/// </summary>
Neg,
/// <summary>
/// Bitwise AND. <see cref="BinaryNumericInstruction"/> /// Bitwise AND. <see cref="BinaryNumericInstruction"/>
/// </summary> /// </summary>
BitAnd, BitAnd,
/// <summary> /// <summary>
/// Bitwise OR. <see cref="BinaryNumericInstruction"/>
/// </summary>
BitOr,
/// <summary>
/// Bitwise XOR. <see cref="BinaryNumericInstruction"/>
/// </summary>
BitXor,
/// <summary>
/// Bitwise NOT. <see cref="UnaryNumericInstruction"/>
/// </summary>
BitNot,
/// <summary>
/// Retrieves the RuntimeArgumentHandle /// Retrieves the RuntimeArgumentHandle
/// </summary> /// </summary>
Arglist, Arglist,
@ -60,6 +92,7 @@ namespace ICSharpCode.Decompiler.IL
/// <see cref="BranchInstruction"/> /// <see cref="BranchInstruction"/>
/// </summary> /// </summary>
Branch, Branch,
Leave,
/// <summary> /// <summary>
/// Breakpoint instruction. /// Breakpoint instruction.
/// </summary> /// </summary>
@ -102,9 +135,66 @@ namespace ICSharpCode.Decompiler.IL
/// Call a method. /// Call a method.
/// </summary> /// </summary>
Call, Call,
/// <summary>
/// Call a method using virtual dispatch.
/// </summary>
CallVirt,
/// <summary>
/// Checks that the float on top of the stack is not NaN or infinite.
/// </summary>
Ckfinite, Ckfinite,
/// <summary>
/// Numeric cast. <see cref="ConvInstruction"/>
/// </summary>
Conv, Conv,
Div, /// <summary>
/// Loads the value of a variable. (ldarg/ldloc)
/// <see cref="LoadVarInstruction"/>
/// </summary>
LoadVar, LoadVar,
/// <summary>
/// Loads the address of a variable as managed ref. (ldarga/ldloca)
/// <see cref="LoadVarInstruction"/>
/// </summary>
LoadVarAddress,
/// <summary>
/// Stores a value into a variable. (starg/stloc)
/// <see cref="StoreVarInstruction"/>
/// </summary>
StoreVar,
/// <summary>
/// Loads a constant string. <see cref="ConstantStringInstruction"/>
/// </summary>
LdStr,
/// <summary>
/// Loads a constant 32-bit integer. <see cref="ConstantI4Instruction"/>
/// </summary>
LdcI4,
/// <summary>
/// Loads a constant 64-bit integer. <see cref="ConstantI8Instruction"/>
/// </summary>
LdcI8,
/// <summary>
/// Loads a constant floating point number. <see cref="ConstantFloatInstruction"/>
/// </summary>
LdcF,
/// <summary>
/// Loads a null reference.
/// </summary>
LdNull,
/// <summary>
/// Returns from the current method or lambda.
/// <see cref="UnaryInstruction"/> or <see cref="SimpleInstruction"/>, depending on whether
/// the method has return type void.
/// </summary>
Ret,
/// <summary>
/// Shift left. <see cref="BinaryNumericInstruction"/>
/// </summary>
Shl,
/// <summary>
/// Shift right. <see cref="BinaryNumericInstruction"/>
/// </summary>
Shr,
} }
} }

14
ICSharpCode.Decompiler/IL/Instructions/Prefix.cs

@ -18,18 +18,4 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
bool IsVolatile { get; set; } bool IsVolatile { get; set; }
} }
[Flags]
enum NoPrefixFlags : byte
{
None = 0,
TypeCheck = 0x01,
RangeCheck = 0x02,
NullCheck = 0x04,
}
interface ISupportsNoPrefix
{
NoPrefixFlags NoPrefix { get; set; }
}
} }

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

@ -12,10 +12,52 @@ namespace ICSharpCode.Decompiler.IL
class SimpleInstruction(OpCode opCode) : ILInstruction(opCode) class SimpleInstruction(OpCode opCode) : ILInstruction(opCode)
{ {
public override bool IsPeeking { get { return false; } } public override bool IsPeeking { get { return false; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
}
} }
class PeekInstruction(OpCode opCode = OpCode.Peek) : ILInstruction(opCode) class PeekInstruction(OpCode opCode = OpCode.Peek) : ILInstruction(opCode)
{ {
public override bool IsPeeking { get { return true; } } public override bool IsPeeking { get { return true; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
}
}
class ConstantStringInstruction(public readonly string Value) : SimpleInstruction(OpCode.LdStr)
{
public override void WriteTo(ITextOutput output)
{
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
}
class ConstantI4Instruction(public readonly int Value) : SimpleInstruction(OpCode.LdcI4)
{
public override void WriteTo(ITextOutput output)
{
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
}
class ConstantI8Instruction(public readonly long Value) : SimpleInstruction(OpCode.LdcI8)
{
public override void WriteTo(ITextOutput output)
{
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
}
class ConstantFloatInstruction(public readonly double Value) : SimpleInstruction(OpCode.LdcI8)
{
public override void WriteTo(ITextOutput output)
{
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
} }
} }

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

@ -6,20 +6,55 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
abstract class UnaryInstruction(OpCode opCode) : ILInstruction(opCode) class UnaryInstruction(OpCode opCode) : ILInstruction(opCode)
{ {
public ILInstruction Operand = Pop; public ILInstruction Operand = Pop;
public override bool IsPeeking { get { return Operand.IsPeeking; } } public override bool IsPeeking { get { return Operand.IsPeeking; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
Operand.WriteTo(output);
output.Write(')');
}
} }
class LogicNotInstruction() : UnaryInstruction(OpCode.LogicNot) class LogicNotInstruction() : UnaryInstruction(OpCode.LogicNot)
{ {
} }
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(')');
}
}
class ConvInstruction( class ConvInstruction(
public readonly StackType FromType, public readonly PrimitiveType ToType, public readonly OverflowMode ConvMode public readonly StackType FromType, public readonly PrimitiveType ToType, public readonly OverflowMode ConvMode
) : UnaryInstruction(OpCode.Conv) ) : 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(')');
}
} }
} }

25
ICSharpCode.Decompiler/IL/Instructions/VarInstructions.cs

@ -4,10 +4,31 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL.Instructions namespace ICSharpCode.Decompiler.IL
{ {
class LoadVarInstruction(public readonly ILVariable Variable) : ILInstruction(OpCode.LoadVar) class LoadVarInstruction(public readonly ILVariable Variable, OpCode opCode = OpCode.LoadVar) : ILInstruction(opCode)
{ {
public override bool IsPeeking { get { return false; } } public override bool IsPeeking { get { return false; } }
public override void WriteTo(ITextOutput output)
{
if (OpCode != OpCode.LoadVar) {
output.Write(OpCode);
output.Write(' ');
}
output.WriteReference(Variable.ToString(), Variable, isLocal: true);
}
}
class StoreVarInstruction(public readonly ILVariable Variable) : UnaryInstruction(OpCode.StoreVar)
{
public override bool IsPeeking { get { return false; } }
public override void WriteTo(ITextOutput output)
{
output.WriteReference(Variable.ToString(), Variable, isLocal: true);
output.Write(" = ");
Operand.WriteTo(output);
}
} }
} }

4
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -53,6 +53,10 @@
<HintPath>..\..\packages\NUnit.2.6.3\lib\nunit.framework.dll</HintPath> <HintPath>..\..\packages\NUnit.2.6.3\lib\nunit.framework.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Collections.Immutable, Version=1.1.22.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.Bcl.Immutable.1.1.22-beta\lib\portable-net45+win8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="System.Core"> <Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework> <RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference> </Reference>

1
ICSharpCode.Decompiler/Tests/packages.config

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="DiffLib" version="1.0.0.55" /> <package id="DiffLib" version="1.0.0.55" />
<package id="Microsoft.Bcl.Immutable" version="1.1.22-beta" targetFramework="net45" />
<package id="NUnit" version="2.6.3" targetFramework="net45" /> <package id="NUnit" version="2.6.3" targetFramework="net45" />
</packages> </packages>

2
ICSharpCode.Decompiler/Util/Interval.cs

@ -11,7 +11,7 @@ namespace ICSharpCode.Decompiler
/// Represents a half-open interval. /// Represents a half-open interval.
/// The start position is inclusive; but the end position is exclusive. /// The start position is inclusive; but the end position is exclusive.
/// </summary> /// </summary>
struct Interval public struct Interval
{ {
public static readonly Interval Empty = new Interval(0, 0); public static readonly Interval Empty = new Interval(0, 0);

5
ILSpy/App.xaml.cs

@ -87,14 +87,13 @@ namespace ICSharpCode.ILSpy
compositionContainer = new CompositionContainer(catalog); compositionContainer = new CompositionContainer(catalog);
Languages.Initialize(compositionContainer);
if (!System.Diagnostics.Debugger.IsAttached) { if (!System.Diagnostics.Debugger.IsAttached) {
AppDomain.CurrentDomain.UnhandledException += ShowErrorBox; AppDomain.CurrentDomain.UnhandledException += ShowErrorBox;
Dispatcher.CurrentDispatcher.UnhandledException += Dispatcher_UnhandledException; Dispatcher.CurrentDispatcher.UnhandledException += Dispatcher_UnhandledException;
} }
TaskScheduler.UnobservedTaskException += DotNet40_UnobservedTaskException; TaskScheduler.UnobservedTaskException += DotNet40_UnobservedTaskException;
Languages.Initialize(compositionContainer);
EventManager.RegisterClassHandler(typeof(Window), EventManager.RegisterClassHandler(typeof(Window),
Hyperlink.RequestNavigateEvent, Hyperlink.RequestNavigateEvent,
new RequestNavigateEventHandler(Window_RequestNavigate)); new RequestNavigateEventHandler(Window_RequestNavigate));

6
ILSpy/ILSpy.csproj

@ -23,6 +23,7 @@
<AssemblyOriginatorKeyFile>..\NRefactory\ICSharpCode.NRefactory.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\NRefactory\ICSharpCode.NRefactory.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign> <DelaySign>False</DelaySign>
<AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode> <AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode>
<LangVersion>experimental</LangVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' "> <PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
@ -57,6 +58,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
@ -78,6 +80,10 @@
<RequiredTargetFramework>3.0</RequiredTargetFramework> <RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Collections.Immutable, Version=1.1.22.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Immutable.1.1.22-beta\lib\portable-net45+win8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition"> <Reference Include="System.ComponentModel.Composition">
<RequiredTargetFramework>4.0</RequiredTargetFramework> <RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference> </Reference>

71
ILSpy/Languages/ILAstLanguage.cs

@ -15,34 +15,29 @@
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // 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 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
/*
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.ILAst; using ICSharpCode.Decompiler.IL;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
#if DEBUG #if DEBUG
/// <summary> /// <summary>
/// Represents the ILAst "language" used for debugging purposes. /// Represents the ILAst "language" used for debugging purposes.
/// </summary> /// </summary>
sealed class ILAstLanguage : Language abstract class ILAstLanguage(string name) : Language
{ {
string name;
bool inlineVariables = true; bool inlineVariables = true;
ILAstOptimizationStep? abortBeforeStep; //ILAstOptimizationStep? abortBeforeStep;
public override string Name { public override string Name { get; } = name;
get { /*
return name;
}
}
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
if (!method.HasBody) { if (!method.HasBody) {
@ -82,32 +77,50 @@ namespace ICSharpCode.ILSpy
node.WriteTo(output); node.WriteTo(output);
output.WriteLine(); output.WriteLine();
} }
} }*/
internal static IEnumerable<ILAstLanguage> GetDebugLanguages() internal static IEnumerable<ILAstLanguage> GetDebugLanguages()
{ {
yield return new ILAstLanguage { name = "ILAst (unoptimized)", inlineVariables = false }; yield return new TypedIL();
string nextName = "ILAst (variable splitting)"; //yield return new ILAstLanguage { name = "ILAst (unoptimized)", inlineVariables = false };
foreach (ILAstOptimizationStep step in Enum.GetValues(typeof(ILAstOptimizationStep))) { //string nextName = "ILAst (variable splitting)";
yield return new ILAstLanguage { name = nextName, abortBeforeStep = step }; //foreach (ILAstOptimizationStep step in Enum.GetValues(typeof(ILAstOptimizationStep))) {
nextName = "ILAst (after " + step + ")"; // yield return new ILAstLanguage { name = nextName, abortBeforeStep = step };
// nextName = "ILAst (after " + step + ")";
} //}
} }
public override string FileExtension { public override string FileExtension
get { {
get
{
return ".il"; return ".il";
} }
} }
public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider = null) public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider = null)
{ {
PlainTextOutput output = new PlainTextOutput(); PlainTextOutput output = new PlainTextOutput();
t.WriteTo(output, includeNamespace ? ILNameSyntax.TypeName : ILNameSyntax.ShortTypeName); t.WriteTo(output, includeNamespace ? ILNameSyntax.TypeName : ILNameSyntax.ShortTypeName);
return output.ToString(); return output.ToString();
} }
}
#endif class TypedIL() : ILAstLanguage("Typed IL")
{
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
base.DecompileMethod(method, output, options);
if (!method.HasBody)
return;
ILReader reader = new ILReader(method.Body);
foreach (var inst in reader.ReadInstructions()) {
output.WriteDefinition("IL_" + inst.ILRange.Start.ToString("x2"), inst.ILRange.Start);
output.Write(": ");
inst.WriteTo(output);
output.WriteLine();
}
}
}
}
#endif
} }
*/

9
ILSpy/Languages/ILLanguage.cs

@ -21,6 +21,7 @@ using System.Collections.Generic;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Disassembler;
using Mono.Cecil; using Mono.Cecil;
using System.ComponentModel.Composition;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
@ -31,14 +32,10 @@ namespace ICSharpCode.ILSpy
/// Currently comes in two versions: /// Currently comes in two versions:
/// flat IL (detectControlStructure=false) and structured IL (detectControlStructure=true). /// flat IL (detectControlStructure=false) and structured IL (detectControlStructure=true).
/// </remarks> /// </remarks>
[Export(typeof(Language))]
public class ILLanguage : Language public class ILLanguage : Language
{ {
private readonly bool detectControlStructure; private readonly bool detectControlStructure = true;
public ILLanguage(bool detectControlStructure)
{
this.detectControlStructure = detectControlStructure;
}
public override string Name { public override string Name {
get { return "IL"; } get { return "IL"; }

3
ILSpy/Languages/Languages.cs

@ -40,9 +40,8 @@ namespace ICSharpCode.ILSpy
{ {
List<Language> languages = new List<Language>(); List<Language> languages = new List<Language>();
languages.AddRange(composition.GetExportedValues<Language>()); languages.AddRange(composition.GetExportedValues<Language>());
languages.Add(new ILLanguage(true));
#if DEBUG #if DEBUG
//languages.AddRange(ILAstLanguage.GetDebugLanguages()); languages.AddRange(ILAstLanguage.GetDebugLanguages());
//languages.AddRange(CSharpLanguage.GetDebugLanguages()); //languages.AddRange(CSharpLanguage.GetDebugLanguages());
#endif #endif
allLanguages = languages.AsReadOnly(); allLanguages = languages.AsReadOnly();

2
ILSpy/Properties/app.config.template

@ -13,7 +13,7 @@
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="ICSharpCode.AvalonEdit" publicKeyToken="9cc39be672370310" culture="neutral"/> <assemblyIdentity name="ICSharpCode.AvalonEdit" publicKeyToken="9cc39be672370310" culture="neutral"/>
<bindingRedirect oldVersion="4.1.0.0-99.9.9.9" newVersion="4.2.0.8752"/> <bindingRedirect oldVersion="4.1.0.0-99.9.9.9" newVersion="4.4.2.9744"/>
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="ICSharpCode.NRefactory" publicKeyToken="d4bfe873e7598c49" culture="neutral"/> <assemblyIdentity name="ICSharpCode.NRefactory" publicKeyToken="d4bfe873e7598c49" culture="neutral"/>

39
ILSpy/TextView/DecompilerTextView.cs

@ -460,35 +460,16 @@ namespace ICSharpCode.ILSpy.TextView
Thread thread = new Thread(new ThreadStart( Thread thread = new Thread(new ThreadStart(
delegate { delegate {
#if DEBUG try {
if (System.Diagnostics.Debugger.IsAttached) { AvalonEditTextOutput textOutput = new AvalonEditTextOutput();
try { textOutput.LengthLimit = outputLengthLimit;
AvalonEditTextOutput textOutput = new AvalonEditTextOutput(); DecompileNodes(context, textOutput);
textOutput.LengthLimit = outputLengthLimit; textOutput.PrepareDocument();
DecompileNodes(context, textOutput); tcs.SetResult(textOutput);
textOutput.PrepareDocument(); } catch (OperationCanceledException) {
tcs.SetResult(textOutput); tcs.SetCanceled();
} catch (OutputLengthExceededException ex) { } catch (Exception ex) {
tcs.SetException(ex); tcs.SetException(ex);
} catch (AggregateException ex) {
tcs.SetException(ex.InnerExceptions);
} catch (OperationCanceledException) {
tcs.SetCanceled();
}
} else
#endif
{
try {
AvalonEditTextOutput textOutput = new AvalonEditTextOutput();
textOutput.LengthLimit = outputLengthLimit;
DecompileNodes(context, textOutput);
textOutput.PrepareDocument();
tcs.SetResult(textOutput);
} catch (OperationCanceledException) {
tcs.SetCanceled();
} catch (Exception ex) {
tcs.SetException(ex);
}
} }
})); }));
thread.Start(); thread.Start();

1
ILSpy/packages.config

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="AvalonEdit" version="4.4.2.9744" targetFramework="net45" /> <package id="AvalonEdit" version="4.4.2.9744" targetFramework="net45" />
<package id="Microsoft.Bcl.Immutable" version="1.1.22-beta" targetFramework="net45" />
</packages> </packages>

77
Mono.Cecil/Mono.Cecil.Cil/MethodBody.cs

@ -33,7 +33,8 @@ using Mono.Collections.Generic;
namespace Mono.Cecil.Cil { namespace Mono.Cecil.Cil {
public sealed class MethodBody : IVariableDefinitionProvider { public sealed class MethodBody : IVariableDefinitionProvider
{
readonly internal MethodDefinition method; readonly internal MethodDefinition method;
@ -49,90 +50,103 @@ namespace Mono.Cecil.Cil {
internal Collection<VariableDefinition> variables; internal Collection<VariableDefinition> variables;
Scope scope; Scope scope;
public MethodDefinition Method { public MethodDefinition Method
{
get { return method; } get { return method; }
} }
public int MaxStackSize { public int MaxStackSize
{
get { return max_stack_size; } get { return max_stack_size; }
set { max_stack_size = value; } set { max_stack_size = value; }
} }
public int CodeSize { public int CodeSize
{
get { return code_size; } get { return code_size; }
} }
public bool InitLocals { public bool InitLocals
{
get { return init_locals; } get { return init_locals; }
set { init_locals = value; } set { init_locals = value; }
} }
public MetadataToken LocalVarToken { public MetadataToken LocalVarToken
{
get { return local_var_token; } get { return local_var_token; }
set { local_var_token = value; } set { local_var_token = value; }
} }
public Collection<Instruction> Instructions { public Collection<Instruction> Instructions
get { return instructions ?? (instructions = new InstructionCollection ()); } {
get { return instructions ?? (instructions = new InstructionCollection()); }
} }
public bool HasExceptionHandlers { public bool HasExceptionHandlers
get { return !exceptions.IsNullOrEmpty (); } {
get { return !exceptions.IsNullOrEmpty(); }
} }
public Collection<ExceptionHandler> ExceptionHandlers { public Collection<ExceptionHandler> ExceptionHandlers
get { return exceptions ?? (exceptions = new Collection<ExceptionHandler> ()); } {
get { return exceptions ?? (exceptions = new Collection<ExceptionHandler>()); }
} }
public bool HasVariables { public bool HasVariables
get { return !variables.IsNullOrEmpty (); } {
get { return !variables.IsNullOrEmpty(); }
} }
public Collection<VariableDefinition> Variables { public Collection<VariableDefinition> Variables
get { return variables ?? (variables = new VariableDefinitionCollection ()); } {
get { return variables ?? (variables = new VariableDefinitionCollection()); }
} }
public Scope Scope { public Scope Scope
{
get { return scope; } get { return scope; }
set { scope = value; } set { scope = value; }
} }
public ParameterDefinition ThisParameter { public ParameterDefinition ThisParameter
get { {
get
{
if (method == null || method.DeclaringType == null) if (method == null || method.DeclaringType == null)
throw new NotSupportedException (); throw new NotSupportedException();
if (!method.HasThis) if (!method.HasThis)
return null; return null;
if (this_parameter == null) if (this_parameter == null)
Interlocked.CompareExchange (ref this_parameter, ThisParameterFor (method), null); Interlocked.CompareExchange(ref this_parameter, ThisParameterFor(method), null);
return this_parameter; return this_parameter;
} }
} }
static ParameterDefinition ThisParameterFor (MethodDefinition method) static ParameterDefinition ThisParameterFor(MethodDefinition method)
{ {
var declaring_type = method.DeclaringType; var declaring_type = method.DeclaringType;
var type = declaring_type.IsValueType || declaring_type.IsPrimitive var type = declaring_type.IsValueType || declaring_type.IsPrimitive
? new PointerType (declaring_type) ? new PointerType(declaring_type)
: declaring_type as TypeReference; : declaring_type as TypeReference;
return new ParameterDefinition (type, method); return new ParameterDefinition(type, method);
} }
public MethodBody (MethodDefinition method) public MethodBody(MethodDefinition method)
{ {
this.method = method; this.method = method;
} }
public ILProcessor GetILProcessor () public ILProcessor GetILProcessor()
{ {
return new ILProcessor (this); return new ILProcessor(this);
} }
public BlobReader GetILReader () public BlobReader GetILReader()
{ {
return code_reader; return code_reader;
} }
@ -144,7 +158,12 @@ namespace Mono.Cecil.Cil {
return reader.LookupToken(t); return reader.LookupToken(t);
}); });
} }
}
public string LookupStringToken(MetadataToken token)
{
return method.Module.Image.UserStringHeap.Read(token.RID);
}
}
public interface IVariableDefinitionProvider { public interface IVariableDefinitionProvider {
bool HasVariables { get; } bool HasVariables { get; }

Loading…
Cancel
Save