Browse Source

Make assignment ILAst opcodes return the assigned value

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
11ec5f24a7
  1. 5
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 6
      ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs
  3. 3
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  4. 1
      ICSharpCode.Decompiler/IL/BlockBuilder.cs
  5. 28
      ICSharpCode.Decompiler/IL/ILReader.cs
  6. 11
      ICSharpCode.Decompiler/IL/Instructions.cs
  7. 13
      ICSharpCode.Decompiler/IL/Instructions.tt
  8. 4
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  9. 3
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  10. 7
      ICSharpCode.Decompiler/IL/TransformingVisitor.cs

5
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -234,9 +234,8 @@ namespace ICSharpCode.Decompiler.CSharp
ConvertedExpression Assignment(ConvertedExpression left, ConvertedExpression right) ConvertedExpression Assignment(ConvertedExpression left, ConvertedExpression right)
{ {
return new ConvertedExpression( return new AssignmentExpression(left.Expression, right.ConvertTo(left.Type, this))
new AssignmentExpression(left.Expression, right.ConvertTo(left.Type, this)), .WithTypeInfo(left.Type);
left.Type);
} }
protected internal override ConvertedExpression VisitAdd(Add inst) protected internal override ConvertedExpression VisitAdd(Add inst)

6
ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs

@ -19,11 +19,17 @@
using System; using System;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp namespace ICSharpCode.Decompiler.CSharp
{ {
static class NRefactoryExtensions static class NRefactoryExtensions
{ {
public static ConvertedExpression WithTypeInfo(this Expression expr, IType type)
{
return new ConvertedExpression(expr, type);
}
public static T WithAnnotation<T>(this T node, object annotation) where T : AstNode public static T WithAnnotation<T>(this T node, object annotation) where T : AstNode
{ {
if (annotation != null) if (annotation != null)

3
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -150,7 +150,10 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
BlockStatement blockStatement = new BlockStatement(); BlockStatement blockStatement = new BlockStatement();
foreach (var block in container.Blocks) { foreach (var block in container.Blocks) {
if (block.IncomingEdgeCount > 1 || block != container.EntryPoint) {
// If there are any incoming branches to this block, add a label:
blockStatement.Add(new LabelStatement { Label = block.Label }); blockStatement.Add(new LabelStatement { Label = block.Label });
}
foreach (var inst in block.Instructions) { foreach (var inst in block.Instructions) {
blockStatement.Add(Convert(inst)); blockStatement.Add(Convert(inst));
} }

1
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -69,6 +69,7 @@ namespace ICSharpCode.Decompiler.IL
} }
var variable = new ILVariable(VariableKind.Exception, eh.CatchType, handlerBlock.ILRange.Start); var variable = new ILVariable(VariableKind.Exception, eh.CatchType, handlerBlock.ILRange.Start);
variable.Name = "ex";
handlerBlock.EntryPoint.Instructions.Add(new LdLoc(variable)); handlerBlock.EntryPoint.Instructions.Add(new LdLoc(variable));
ILInstruction filter; ILInstruction filter;

28
ICSharpCode.Decompiler/IL/ILReader.cs

@ -493,21 +493,21 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Starg_S: case ILOpCode.Starg_S:
return Starg(reader.ReadByte()); return Starg(reader.ReadByte());
case ILOpCode.Stind_I1: case ILOpCode.Stind_I1:
return new StObj(value: Pop(), target: Pop(), type: typeSystem.SByte); return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.SByte));
case ILOpCode.Stind_I2: case ILOpCode.Stind_I2:
return new StObj(value: Pop(), target: Pop(), type: typeSystem.Int16); return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Int16));
case ILOpCode.Stind_I4: case ILOpCode.Stind_I4:
return new StObj(value: Pop(), target: Pop(), type: typeSystem.Int32); return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Int32));
case ILOpCode.Stind_I8: case ILOpCode.Stind_I8:
return new StObj(value: Pop(), target: Pop(), type: typeSystem.Int64); return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Int64));
case ILOpCode.Stind_R4: case ILOpCode.Stind_R4:
return new StObj(value: Pop(), target: Pop(), type: typeSystem.Single); return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Single));
case ILOpCode.Stind_R8: case ILOpCode.Stind_R8:
return new StObj(value: Pop(), target: Pop(), type: typeSystem.Double); return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Double));
case ILOpCode.Stind_I: case ILOpCode.Stind_I:
return new StObj(value: Pop(), target: Pop(), type: typeSystem.IntPtr); return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.IntPtr));
case ILOpCode.Stind_Ref: case ILOpCode.Stind_Ref:
return new StObj(value: Pop(), target: Pop(), type: typeSystem.Object); return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Object));
case ILOpCode.Stloc: case ILOpCode.Stloc:
return Stloc(reader.ReadUInt16()); return Stloc(reader.ReadUInt16());
case ILOpCode.Stloc_S: case ILOpCode.Stloc_S:
@ -535,7 +535,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
var type = (TypeReference)ReadAndDecodeMetadataToken(); var type = (TypeReference)ReadAndDecodeMetadataToken();
var ld = new LdObj(Pop(), type); var ld = new LdObj(Pop(), type);
return new StObj(Pop(), ld, type); return new Void(new StObj(Pop(), ld, type));
} }
case ILOpCode.Initobj: case ILOpCode.Initobj:
return new InitObj(Pop(), (TypeReference)ReadAndDecodeMetadataToken()); return new InitObj(Pop(), (TypeReference)ReadAndDecodeMetadataToken());
@ -561,7 +561,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldflda: case ILOpCode.Ldflda:
return new LdFlda(Pop(), (FieldReference)ReadAndDecodeMetadataToken()); return new LdFlda(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Stfld: case ILOpCode.Stfld:
return new StFld(value: Pop(), target: Pop(), field: (FieldReference)ReadAndDecodeMetadataToken()); return new Void(new StFld(value: Pop(), target: Pop(), field: (FieldReference)ReadAndDecodeMetadataToken()));
case ILOpCode.Ldlen: case ILOpCode.Ldlen:
return new LdLen(Pop()); return new LdLen(Pop());
case ILOpCode.Ldobj: case ILOpCode.Ldobj:
@ -571,7 +571,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldsflda: case ILOpCode.Ldsflda:
return new LdsFlda((FieldReference)ReadAndDecodeMetadataToken()); return new LdsFlda((FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Stsfld: case ILOpCode.Stsfld:
return new StsFld(Pop(), (FieldReference)ReadAndDecodeMetadataToken()); return new Void(new StsFld(Pop(), (FieldReference)ReadAndDecodeMetadataToken()));
case ILOpCode.Ldtoken: case ILOpCode.Ldtoken:
return new LdToken((MemberReference)ReadAndDecodeMetadataToken()); return new LdToken((MemberReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldvirtftn: case ILOpCode.Ldvirtftn:
@ -599,7 +599,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Stelem_Ref: case ILOpCode.Stelem_Ref:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Stobj: case ILOpCode.Stobj:
return new StObj(value: Pop(), target: Pop(), type: (TypeReference)ReadAndDecodeMetadataToken()); return new Void(new StObj(value: Pop(), target: Pop(), type: (TypeReference)ReadAndDecodeMetadataToken()));
case ILOpCode.Throw: case ILOpCode.Throw:
return new Throw(Pop()); return new Throw(Pop());
case ILOpCode.Unbox: case ILOpCode.Unbox:
@ -648,7 +648,7 @@ namespace ICSharpCode.Decompiler.IL
private ILInstruction Starg(ushort v) private ILInstruction Starg(ushort v)
{ {
return new StLoc(Pop(), parameterVariables[v]); return new Void(new StLoc(Pop(), parameterVariables[v]));
} }
private ILInstruction Ldloc(ushort v) private ILInstruction Ldloc(ushort v)
@ -663,7 +663,7 @@ namespace ICSharpCode.Decompiler.IL
private ILInstruction Stloc(ushort v) private ILInstruction Stloc(ushort v)
{ {
return new StLoc(Pop(), localVariables[v]); return new Void(new StLoc(Pop(), localVariables[v]));
} }
private ILInstruction DecodeConstrainedCall() private ILInstruction DecodeConstrainedCall()

11
ICSharpCode.Decompiler/IL/Instructions.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
@ -622,6 +623,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
this.Filter = filter; this.Filter = filter;
this.Body = body; this.Body = body;
Debug.Assert(variable != null);
this.variable = variable; this.variable = variable;
} }
ILInstruction filter; ILInstruction filter;
@ -825,6 +827,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
public LdLoc(ILVariable variable) : base(OpCode.LdLoc) public LdLoc(ILVariable variable) : base(OpCode.LdLoc)
{ {
Debug.Assert(variable != null);
this.variable = variable; this.variable = variable;
} }
readonly ILVariable variable; readonly ILVariable variable;
@ -848,6 +851,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
public LdLoca(ILVariable variable) : base(OpCode.LdLoca) public LdLoca(ILVariable variable) : base(OpCode.LdLoca)
{ {
Debug.Assert(variable != null);
this.variable = variable; this.variable = variable;
} }
public override StackType ResultType { get { return StackType.Ref; } } public override StackType ResultType { get { return StackType.Ref; } }
@ -872,6 +876,7 @@ namespace ICSharpCode.Decompiler.IL
public StLoc(ILInstruction value, ILVariable variable) : base(OpCode.StLoc) public StLoc(ILInstruction value, ILVariable variable) : base(OpCode.StLoc)
{ {
this.Value = value; this.Value = value;
Debug.Assert(variable != null);
this.variable = variable; this.variable = variable;
} }
ILInstruction value; ILInstruction value;
@ -896,10 +901,10 @@ namespace ICSharpCode.Decompiler.IL
this.Value = this.value.Inline(flagsBefore, instructionStack, out finished); this.Value = this.value.Inline(flagsBefore, instructionStack, out finished);
return this; return this;
} }
public override StackType ResultType { get { return StackType.Void; } }
readonly ILVariable variable; readonly ILVariable variable;
/// <summary>Returns the variable operand.</summary> /// <summary>Returns the variable operand.</summary>
public ILVariable Variable { get { return variable; } } public ILVariable Variable { get { return variable; } }
public override StackType ResultType { get { return variable.Type.GetStackType(); } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return value.Flags; return value.Flags;
@ -1306,10 +1311,10 @@ namespace ICSharpCode.Decompiler.IL
public bool IsVolatile { get; set; } public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary> /// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; } public byte UnalignedPrefix { get; set; }
public override StackType ResultType { get { return StackType.Void; } }
readonly FieldReference field; readonly FieldReference field;
/// <summary>Returns the field operand.</summary> /// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } } public FieldReference Field { get { return field; } }
public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return target.Flags | value.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow; return target.Flags | value.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
@ -1427,10 +1432,10 @@ namespace ICSharpCode.Decompiler.IL
public bool IsVolatile { get; set; } public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary> /// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; } public byte UnalignedPrefix { get; set; }
public override StackType ResultType { get { return StackType.Void; } }
readonly FieldReference field; readonly FieldReference field;
/// <summary>Returns the field operand.</summary> /// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } } public FieldReference Field { get { return field; } }
public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return value.Flags | InstructionFlags.SideEffect; return value.Flags | InstructionFlags.SideEffect;

13
ICSharpCode.Decompiler/IL/Instructions.tt

@ -106,7 +106,8 @@
new OpCode("ldloca", "Loads the address of a local variable. (ldarga/ldloca)", new OpCode("ldloca", "Loads the address of a local variable. (ldarga/ldloca)",
CustomClassName("LdLoca"), NoArguments, ResultType("Ref"), HasVariableOperand), CustomClassName("LdLoca"), NoArguments, ResultType("Ref"), HasVariableOperand),
new OpCode("stloc", "Stores a value into a local variable. (starg/stloc)", new OpCode("stloc", "Stores a value into a local variable. (starg/stloc)",
CustomClassName("StLoc"), CustomArguments("value"), VoidResult, HasVariableOperand), CustomClassName("StLoc"), CustomArguments("value"), HasVariableOperand,
ResultType("variable.Type.GetStackType()")),
new OpCode("ldstr", "Loads a constant string.", new OpCode("ldstr", "Loads a constant string.",
CustomClassName("LdStr"), LoadConstant("string"), ResultType("O")), CustomClassName("LdStr"), LoadConstant("string"), ResultType("O")),
new OpCode("ldc.i4", "Loads a constant 32-bit integer.", new OpCode("ldc.i4", "Loads a constant 32-bit integer.",
@ -136,14 +137,18 @@
new OpCode("ldflda", "Load address of instance field", new OpCode("ldflda", "Load address of instance field",
CustomClassName("LdFlda"), CustomArguments("target"), MayThrow, HasFieldOperand, ResultType("Ref")), CustomClassName("LdFlda"), CustomArguments("target"), MayThrow, HasFieldOperand, ResultType("Ref")),
new OpCode("stfld", "Store value to instance field", new OpCode("stfld", "Store value to instance field",
CustomClassName("StFld"), CustomArguments("target", "value"), MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, VoidResult, HasFieldOperand), CustomClassName("StFld"), CustomArguments("target", "value"),
MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, HasFieldOperand,
ResultType("field.FieldType.GetStackType()")),
new OpCode("ldsfld", "Load static field", new OpCode("ldsfld", "Load static field",
CustomClassName("LdsFld"), NoArguments, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, CustomClassName("LdsFld"), NoArguments, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix,
HasFieldOperand, ResultType("field.FieldType.GetStackType()")), HasFieldOperand, ResultType("field.FieldType.GetStackType()")),
new OpCode("ldsflda", "Load static field address", new OpCode("ldsflda", "Load static field address",
CustomClassName("LdsFlda"), NoArguments, ResultType("Ref"), HasFieldOperand), CustomClassName("LdsFlda"), NoArguments, ResultType("Ref"), HasFieldOperand),
new OpCode("stsfld", "Store value to static field", new OpCode("stsfld", "Store value to static field",
CustomClassName("StsFld"), CustomArguments("value"), MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, VoidResult, HasFieldOperand), CustomClassName("StsFld"), CustomArguments("value"),
MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, HasFieldOperand,
ResultType("field.FieldType.GetStackType()")),
new OpCode("castclass", "Casts an object to a class.", new OpCode("castclass", "Casts an object to a class.",
CustomClassName("CastClass"), Unary, HasTypeOperand, MayThrow, ResultType("type.GetStackType()")), CustomClassName("CastClass"), Unary, HasTypeOperand, MayThrow, ResultType("type.GetStackType()")),
@ -186,6 +191,7 @@
#> #>
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
@ -635,6 +641,7 @@ namespace ICSharpCode.Decompiler.IL
static Action<OpCode> HasVariableOperand = opCode => { static Action<OpCode> HasVariableOperand = opCode => {
opCode.ConstructorParameters.Add("ILVariable variable"); opCode.ConstructorParameters.Add("ILVariable variable");
opCode.Members.Add("readonly ILVariable variable;"); opCode.Members.Add("readonly ILVariable variable;");
opCode.ConstructorBody.Add("Debug.Assert(variable != null);");
opCode.ConstructorBody.Add("this.variable = variable;"); opCode.ConstructorBody.Add("this.variable = variable;");
opCode.Members.Add("/// <summary>Returns the variable operand.</summary>" + Environment.NewLine opCode.Members.Add("/// <summary>Returns the variable operand.</summary>" + Environment.NewLine
+ "public ILVariable Variable { get { return variable; } }"); + "public ILVariable Variable { get { return variable; } }");

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

@ -90,9 +90,9 @@ namespace ICSharpCode.Decompiler.IL
output.Write(' '); output.Write(' ');
output.WriteReference(TargetLabel, (object)targetBlock ?? TargetILOffset, isLocal: true); output.WriteReference(TargetLabel, (object)targetBlock ?? TargetILOffset, isLocal: true);
if (PopCount != 0) { if (PopCount != 0) {
output.Write(" (pop "); output.Write(" (pops ");
output.Write(PopCount.ToString()); output.Write(PopCount.ToString());
output.Write(')'); output.Write(" element)");
} }
} }
} }

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

@ -46,10 +46,11 @@ namespace ICSharpCode.Decompiler.IL
throw new ArgumentException("Argument must not be of type void", "inst"); throw new ArgumentException("Argument must not be of type void", "inst");
} }
internal static void ValidateChild(ILInstruction inst) internal void ValidateChild(ILInstruction inst)
{ {
if (inst == null) if (inst == null)
throw new ArgumentNullException("inst"); throw new ArgumentNullException("inst");
Debug.Assert(!this.IsDescendantOf(inst), "ILAst must form a tree");
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]

7
ICSharpCode.Decompiler/IL/TransformingVisitor.cs

@ -79,9 +79,12 @@ namespace ICSharpCode.Decompiler.IL
// Wrap the instruction on top of the stack into an inline block, // Wrap the instruction on top of the stack into an inline block,
// and append our void-typed instruction to the end of that block. // and append our void-typed instruction to the end of that block.
var headInst = stack.Pop(); var headInst = stack.Pop();
var nestedBlock = headInst as Block ?? new Block { Instructions = { headInst } }; var nestedBlock = headInst as Block ?? new Block {
Instructions = { headInst },
ILRange = headInst.ILRange
};
nestedBlock.Instructions.Add(inst); nestedBlock.Instructions.Add(inst);
stack.Push(block); stack.Push(nestedBlock);
} else { } else {
// We can't move incomplete instructions into a nested block // We can't move incomplete instructions into a nested block
// or the instruction stack was empty // or the instruction stack was empty

Loading…
Cancel
Save