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

6
ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs

@ -19,11 +19,17 @@ @@ -19,11 +19,17 @@
using System;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp
{
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
{
if (annotation != null)

5
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -150,7 +150,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -150,7 +150,10 @@ namespace ICSharpCode.Decompiler.CSharp
{
BlockStatement blockStatement = new BlockStatement();
foreach (var block in container.Blocks) {
blockStatement.Add(new LabelStatement { Label = block.Label });
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 });
}
foreach (var inst in block.Instructions) {
blockStatement.Add(Convert(inst));
}

1
ICSharpCode.Decompiler/IL/BlockBuilder.cs

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

28
ICSharpCode.Decompiler/IL/ILReader.cs

@ -493,21 +493,21 @@ namespace ICSharpCode.Decompiler.IL @@ -493,21 +493,21 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Starg_S:
return Starg(reader.ReadByte());
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:
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:
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:
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:
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:
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:
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:
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:
return Stloc(reader.ReadUInt16());
case ILOpCode.Stloc_S:
@ -535,7 +535,7 @@ namespace ICSharpCode.Decompiler.IL @@ -535,7 +535,7 @@ namespace ICSharpCode.Decompiler.IL
{
var type = (TypeReference)ReadAndDecodeMetadataToken();
var ld = new LdObj(Pop(), type);
return new StObj(Pop(), ld, type);
return new Void(new StObj(Pop(), ld, type));
}
case ILOpCode.Initobj:
return new InitObj(Pop(), (TypeReference)ReadAndDecodeMetadataToken());
@ -561,7 +561,7 @@ namespace ICSharpCode.Decompiler.IL @@ -561,7 +561,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldflda:
return new LdFlda(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
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:
return new LdLen(Pop());
case ILOpCode.Ldobj:
@ -571,7 +571,7 @@ namespace ICSharpCode.Decompiler.IL @@ -571,7 +571,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldsflda:
return new LdsFlda((FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Stsfld:
return new StsFld(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
return new Void(new StsFld(Pop(), (FieldReference)ReadAndDecodeMetadataToken()));
case ILOpCode.Ldtoken:
return new LdToken((MemberReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldvirtftn:
@ -599,7 +599,7 @@ namespace ICSharpCode.Decompiler.IL @@ -599,7 +599,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Stelem_Ref:
throw new NotImplementedException();
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:
return new Throw(Pop());
case ILOpCode.Unbox:
@ -648,7 +648,7 @@ namespace ICSharpCode.Decompiler.IL @@ -648,7 +648,7 @@ namespace ICSharpCode.Decompiler.IL
private ILInstruction Starg(ushort v)
{
return new StLoc(Pop(), parameterVariables[v]);
return new Void(new StLoc(Pop(), parameterVariables[v]));
}
private ILInstruction Ldloc(ushort v)
@ -663,7 +663,7 @@ namespace ICSharpCode.Decompiler.IL @@ -663,7 +663,7 @@ namespace ICSharpCode.Decompiler.IL
private ILInstruction Stloc(ushort v)
{
return new StLoc(Pop(), localVariables[v]);
return new Void(new StLoc(Pop(), localVariables[v]));
}
private ILInstruction DecodeConstrainedCall()

11
ICSharpCode.Decompiler/IL/Instructions.cs

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

13
ICSharpCode.Decompiler/IL/Instructions.tt

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

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

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

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

@ -46,10 +46,11 @@ namespace ICSharpCode.Decompiler.IL @@ -46,10 +46,11 @@ namespace ICSharpCode.Decompiler.IL
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)
throw new ArgumentNullException("inst");
Debug.Assert(!this.IsDescendantOf(inst), "ILAst must form a tree");
}
[Conditional("DEBUG")]

7
ICSharpCode.Decompiler/IL/TransformingVisitor.cs

@ -79,9 +79,12 @@ namespace ICSharpCode.Decompiler.IL @@ -79,9 +79,12 @@ namespace ICSharpCode.Decompiler.IL
// Wrap the instruction on top of the stack into an inline block,
// and append our void-typed instruction to the end of that block.
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);
stack.Push(block);
stack.Push(nestedBlock);
} else {
// We can't move incomplete instructions into a nested block
// or the instruction stack was empty

Loading…
Cancel
Save