Browse Source

Change representation of conditional branch.

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
b648744380
  1. 18
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  2. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 83
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 4
      ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
  5. 173
      ICSharpCode.Decompiler/IL/Instructions.cs
  6. 186
      ICSharpCode.Decompiler/IL/Instructions.tt
  7. 42
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  8. 156
      ICSharpCode.Decompiler/IL/Instructions/BranchInstruction.cs
  9. 116
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

18
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -46,16 +46,30 @@ namespace ICSharpCode.Decompiler.CSharp @@ -46,16 +46,30 @@ namespace ICSharpCode.Decompiler.CSharp
return new ExpressionStatement(exprBuilder.Convert(inst));
}
protected internal override Statement VisitConditionalBranch(ConditionalBranch inst)
protected internal override Statement VisitIfInstruction(IfInstruction inst)
{
var condition = exprBuilder.ConvertCondition(inst.Condition);
return new IfElseStatement(condition, new GotoStatement(inst.TargetLabel));
var trueStatement = Convert(inst.TrueInst);
var falseStatement = inst.FalseInst.OpCode == OpCode.Nop ? null : Convert(inst.FalseInst);
return new IfElseStatement(condition, trueStatement, falseStatement);
}
protected internal override Statement VisitBranch(Branch inst)
{
return new GotoStatement(inst.TargetLabel);
}
protected internal override Statement VisitThrow(Throw inst)
{
return new ThrowStatement(exprBuilder.Convert(inst.Argument));
}
protected internal override Statement VisitReturn(Return inst)
{
if (inst.Argument == null)
return new ReturnStatement();
return new ReturnStatement(exprBuilder.Convert(inst.Argument));
}
protected internal override Statement VisitBlockContainer(BlockContainer inst)
{

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -76,9 +76,10 @@ @@ -76,9 +76,10 @@
<Compile Include="IL\Instructions\BinaryNumericInstruction.cs" />
<Compile Include="IL\Instructions\Block.cs" />
<Compile Include="IL\Instructions\BlockContainer.cs" />
<Compile Include="IL\Instructions\BranchInstruction.cs" />
<Compile Include="IL\Instructions\Branch.cs" />
<Compile Include="IL\Instructions\CallInstruction.cs" />
<Compile Include="IL\Instructions\Conv.cs" />
<Compile Include="IL\Instructions\IfInstruction.cs" />
<Compile Include="IL\Instructions\ILInstruction.cs" />
<Compile Include="IL\Instructions\InstructionCollection.cs" />
<Compile Include="IL\Instructions\MemoryInstructions.cs" />

83
ICSharpCode.Decompiler/IL/ILReader.cs

@ -89,16 +89,18 @@ namespace ICSharpCode.Decompiler.IL @@ -89,16 +89,18 @@ namespace ICSharpCode.Decompiler.IL
void Warn(string message)
{
Debug.Fail(message);
}
// Dictionary that stores stacks for forward jumps
Dictionary<int, ImmutableArray<StackType>> branchStackDict = new Dictionary<int, ImmutableArray<StackType>>();
void ReadInstructions(Dictionary<int, ImmutableArray<StackType>> outputStacks)
{
instructionBuilder = new List<ILInstruction>();
isBranchTarget = new BitArray(body.CodeSize);
stack.Clear();
// Dictionary that stores stacks for forward jumps
var branchStackDict = new Dictionary<int, ImmutableArray<StackType>>();
branchStackDict.Clear();
while (reader.Position < reader.Length) {
cancellationToken.ThrowIfCancellationRequested();
@ -110,13 +112,6 @@ namespace ICSharpCode.Decompiler.IL @@ -110,13 +112,6 @@ namespace ICSharpCode.Decompiler.IL
stack.Push(decodedInstruction.ResultType);
decodedInstruction.ILRange = new Interval(start, reader.Position);
instructionBuilder.Add(decodedInstruction);
BranchInstruction branch = decodedInstruction as BranchInstruction;
if (branch != null) {
isBranchTarget[branch.TargetILOffset] = true;
if (branch.TargetILOffset >= reader.Position) {
branchStackDict[branch.TargetILOffset] = stack.ToImmutableArray();
}
}
if (decodedInstruction.HasFlag(InstructionFlags.EndPointUnreachable)) {
stack.Clear();
ImmutableArray<StackType> stackFromBranch;
@ -250,9 +245,9 @@ namespace ICSharpCode.Decompiler.IL @@ -250,9 +245,9 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Bne_Un_S:
return DecodeComparisonBranch(true, OpCode.Ceq, OpCode.Ceq, true);
case ILOpCode.Br:
return DecodeUnconditionalBranch(false, OpCode.Branch);
return DecodeUnconditionalBranch(false);
case ILOpCode.Br_S:
return DecodeUnconditionalBranch(true, OpCode.Branch);
return DecodeUnconditionalBranch(true);
case ILOpCode.Break:
return new DebugBreak();
case ILOpCode.Brfalse:
@ -280,7 +275,7 @@ namespace ICSharpCode.Decompiler.IL @@ -280,7 +275,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Clt_Un:
return Comparison(OpCode.Clt_Un, OpCode.Clt_Un);
case ILOpCode.Ckfinite:
return new CkFinite();
return new Ckfinite();
case ILOpCode.Conv_I1:
return new Conv(Pop(), PrimitiveType.I1, OverflowMode.None);
case ILOpCode.Conv_I2:
@ -404,27 +399,27 @@ namespace ICSharpCode.Decompiler.IL @@ -404,27 +399,27 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldftn:
throw new NotImplementedException();
case ILOpCode.Ldind_I1:
return new LdInd(Pop(), typeSystem.SByte);
return new LdObj(Pop(), typeSystem.SByte);
case ILOpCode.Ldind_I2:
return new LdInd(Pop(), typeSystem.Int16);
return new LdObj(Pop(), typeSystem.Int16);
case ILOpCode.Ldind_I4:
return new LdInd(Pop(), typeSystem.Int32);
return new LdObj(Pop(), typeSystem.Int32);
case ILOpCode.Ldind_I8:
return new LdInd(Pop(), typeSystem.Int64);
return new LdObj(Pop(), typeSystem.Int64);
case ILOpCode.Ldind_U1:
return new LdInd(Pop(), typeSystem.Byte);
return new LdObj(Pop(), typeSystem.Byte);
case ILOpCode.Ldind_U2:
return new LdInd(Pop(), typeSystem.UInt16);
return new LdObj(Pop(), typeSystem.UInt16);
case ILOpCode.Ldind_U4:
return new LdInd(Pop(), typeSystem.UInt32);
return new LdObj(Pop(), typeSystem.UInt32);
case ILOpCode.Ldind_R4:
return new LdInd(Pop(), typeSystem.Single);
return new LdObj(Pop(), typeSystem.Single);
case ILOpCode.Ldind_R8:
return new LdInd(Pop(), typeSystem.Double);
return new LdObj(Pop(), typeSystem.Double);
case ILOpCode.Ldind_I:
return new LdInd(Pop(), typeSystem.IntPtr);
return new LdObj(Pop(), typeSystem.IntPtr);
case ILOpCode.Ldind_Ref:
return new LdInd(Pop(), typeSystem.Object);
return new LdObj(Pop(), typeSystem.Object);
case ILOpCode.Ldloc:
return Ldloc(reader.ReadUInt16());
case ILOpCode.Ldloc_S:
@ -439,11 +434,9 @@ namespace ICSharpCode.Decompiler.IL @@ -439,11 +434,9 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldloca_S:
return Ldloca(reader.ReadByte());
case ILOpCode.Leave:
//return DecodeUnconditionalBranch(false, OpCode.Leave);
throw new NotImplementedException();
return DecodeUnconditionalBranch(false, isLeave: true);
case ILOpCode.Leave_S:
//return DecodeUnconditionalBranch(true, OpCode.Leave);
throw new NotImplementedException();
return DecodeUnconditionalBranch(true, isLeave: true);
case ILOpCode.Localloc:
throw new NotImplementedException();
case ILOpCode.Mul:
@ -534,9 +527,9 @@ namespace ICSharpCode.Decompiler.IL @@ -534,9 +527,9 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldelema:
throw new NotImplementedException();
case ILOpCode.Ldfld:
return new Ldfld(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
return new LdFld(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldflda:
return new Ldflda(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
return new LdFlda(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Stfld:
throw new NotImplementedException();
//\return new Stfld(Pop(), Pop(), (FieldReference)ReadAndDecodeMetadataToken());
@ -545,11 +538,11 @@ namespace ICSharpCode.Decompiler.IL @@ -545,11 +538,11 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldobj:
throw new NotImplementedException();
case ILOpCode.Ldsfld:
return new Ldsfld((FieldReference)ReadAndDecodeMetadataToken());
return new LdsFld((FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldsflda:
return new Ldsflda((FieldReference)ReadAndDecodeMetadataToken());
return new LdsFlda((FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Stsfld:
return new Stsfld(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
return new StsFld(Pop(), (FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldtoken:
throw new NotImplementedException();
case ILOpCode.Ldvirtftn:
@ -719,7 +712,8 @@ namespace ICSharpCode.Decompiler.IL @@ -719,7 +712,8 @@ namespace ICSharpCode.Decompiler.IL
if (negate) {
condition = new LogicNot(condition);
}
return new ConditionalBranch(condition, target);
MarkBranchTarget(target);
return new IfInstruction(condition, new Branch(target));
}
ILInstruction DecodeConditionalBranch(bool shortForm, bool negate)
@ -730,16 +724,31 @@ namespace ICSharpCode.Decompiler.IL @@ -730,16 +724,31 @@ namespace ICSharpCode.Decompiler.IL
if (negate) {
condition = new LogicNot(condition);
}
return new ConditionalBranch(condition, target);
MarkBranchTarget(target);
return new IfInstruction(condition, new Branch(target));
}
ILInstruction DecodeUnconditionalBranch(bool shortForm, OpCode opCode)
ILInstruction DecodeUnconditionalBranch(bool shortForm, bool isLeave = false)
{
int target = shortForm ? reader.ReadSByte() : reader.ReadInt32();
target += reader.Position;
return new Branch(target);
int popCount = 0;
if (isLeave) {
popCount = stack.Count;
stack.Clear();
}
MarkBranchTarget(target);
return new Branch(target) { PopCount = popCount };
}
void MarkBranchTarget(int targetILOffset)
{
isBranchTarget[targetILOffset] = true;
if (targetILOffset >= reader.Position) {
branchStackDict[targetILOffset] = stack.ToImmutableArray();
}
}
ILInstruction BinaryNumeric(OpCode opCode, OverflowMode overflowMode = OverflowMode.None)
{
var right = Pop();

4
ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs

@ -24,11 +24,11 @@ using System.Threading.Tasks; @@ -24,11 +24,11 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
static class InstructionOutputExtensions
static partial class InstructionOutputExtensions
{
public static void Write(this ITextOutput output, OpCode opCode)
{
output.Write(opCode.ToString().ToLowerInvariant());
output.Write(originalOpCodeNames[(int)opCode]);
}
public static void Write(this ITextOutput output, StackType stackType)

173
ICSharpCode.Decompiler/IL/Instructions.cs

@ -60,10 +60,10 @@ namespace ICSharpCode.Decompiler.IL @@ -60,10 +60,10 @@ namespace ICSharpCode.Decompiler.IL
BitNot,
/// <summary>Retrieves the RuntimeArgumentHandle.</summary>
Arglist,
/// <summary><c>if (condition) goto target;</c>.</summary>
ConditionalBranch,
/// <summary><c>goto target;</c>.</summary>
/// <summary>Unconditional branch. <c>goto target;</c></summary>
Branch,
/// <summary>If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c></summary>
IfInstruction,
/// <summary>Breakpoint instruction</summary>
DebugBreak,
/// <summary>Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.</summary>
@ -81,7 +81,7 @@ namespace ICSharpCode.Decompiler.IL @@ -81,7 +81,7 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Virtual method call.</summary>
CallVirt,
/// <summary>Checks that the float on top of the stack is not NaN or infinite.</summary>
CkFinite,
Ckfinite,
/// <summary>Numeric cast.</summary>
Conv,
/// <summary>Loads the value of a local variable. (ldarg/ldloc)</summary>
@ -107,21 +107,21 @@ namespace ICSharpCode.Decompiler.IL @@ -107,21 +107,21 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Shift right</summary>
Shr,
/// <summary>Load instance field</summary>
Ldfld,
LdFld,
/// <summary>Load address of instance field</summary>
Ldflda,
LdFlda,
/// <summary>Store value to instance field</summary>
Stfld,
StFld,
/// <summary>Load static field</summary>
Ldsfld,
LdsFld,
/// <summary>Load static field address</summary>
Ldsflda,
LdsFlda,
/// <summary>Store value to static field</summary>
Stsfld,
StsFld,
/// <summary>Test if object is instance of class or interface.</summary>
IsInst,
/// <summary>Indirect load (ref/pointer dereference).</summary>
LdInd,
LdObj,
/// <summary>Unbox a value.</summary>
UnboxAny,
/// <summary>Creates an object instance and calls the constructor.</summary>
@ -363,30 +363,27 @@ namespace ICSharpCode.Decompiler.IL @@ -363,30 +363,27 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary><c>if (condition) goto target;</c>.</summary>
public sealed partial class ConditionalBranch : BranchInstruction
/// <summary>Unconditional branch. <c>goto target;</c></summary>
public sealed partial class Branch : SimpleInstruction
{
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch;
}
public override StackType ResultType { get { return StackType.Void; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitConditionalBranch(this);
return visitor.VisitBranch(this);
}
}
/// <summary><c>goto target;</c>.</summary>
public sealed partial class Branch : BranchInstruction
/// <summary>If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c></summary>
public sealed partial class IfInstruction : ILInstruction
{
public Branch(int targetILOffset) : base(OpCode.Branch, targetILOffset)
{
}
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch;
}
public override StackType ResultType { get { return StackType.Void; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitBranch(this);
return visitor.VisitIfInstruction(this);
}
}
@ -499,9 +496,9 @@ namespace ICSharpCode.Decompiler.IL @@ -499,9 +496,9 @@ namespace ICSharpCode.Decompiler.IL
}
/// <summary>Checks that the float on top of the stack is not NaN or infinite.</summary>
public sealed partial class CkFinite : SimpleInstruction
public sealed partial class Ckfinite : SimpleInstruction
{
public CkFinite() : base(OpCode.CkFinite)
public Ckfinite() : base(OpCode.Ckfinite)
{
}
protected override InstructionFlags ComputeFlags()
@ -511,7 +508,7 @@ namespace ICSharpCode.Decompiler.IL @@ -511,7 +508,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.Void; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitCkFinite(this);
return visitor.VisitCkfinite(this);
}
}
@ -714,9 +711,9 @@ namespace ICSharpCode.Decompiler.IL @@ -714,9 +711,9 @@ namespace ICSharpCode.Decompiler.IL
}
/// <summary>Load instance field</summary>
public sealed partial class Ldfld : UnaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
public sealed partial class LdFld : UnaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
public Ldfld(ILInstruction argument, FieldReference field) : base(OpCode.Ldfld, argument)
public LdFld(ILInstruction argument, FieldReference field) : base(OpCode.LdFld, argument)
{
this.field = field;
}
@ -734,14 +731,14 @@ namespace ICSharpCode.Decompiler.IL @@ -734,14 +731,14 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdfld(this);
return visitor.VisitLdFld(this);
}
}
/// <summary>Load address of instance field</summary>
public sealed partial class Ldflda : UnaryInstruction
public sealed partial class LdFlda : UnaryInstruction
{
public Ldflda(ILInstruction argument, FieldReference field) : base(OpCode.Ldflda, argument)
public LdFlda(ILInstruction argument, FieldReference field) : base(OpCode.LdFlda, argument)
{
this.field = field;
}
@ -755,14 +752,14 @@ namespace ICSharpCode.Decompiler.IL @@ -755,14 +752,14 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.Ref; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdflda(this);
return visitor.VisitLdFlda(this);
}
}
/// <summary>Store value to instance field</summary>
public sealed partial class Stfld : BinaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
public sealed partial class StFld : BinaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
public Stfld(ILInstruction left, ILInstruction right, FieldReference field) : base(OpCode.Stfld, left, right)
public StFld(ILInstruction left, ILInstruction right, FieldReference field) : base(OpCode.StFld, left, right)
{
this.field = field;
}
@ -780,14 +777,14 @@ namespace ICSharpCode.Decompiler.IL @@ -780,14 +777,14 @@ namespace ICSharpCode.Decompiler.IL
public FieldReference Field { get { return field; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitStfld(this);
return visitor.VisitStFld(this);
}
}
/// <summary>Load static field</summary>
public sealed partial class Ldsfld : SimpleInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
public sealed partial class LdsFld : SimpleInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
public Ldsfld(FieldReference field) : base(OpCode.Ldsfld)
public LdsFld(FieldReference field) : base(OpCode.LdsFld)
{
this.field = field;
}
@ -805,14 +802,14 @@ namespace ICSharpCode.Decompiler.IL @@ -805,14 +802,14 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdsfld(this);
return visitor.VisitLdsFld(this);
}
}
/// <summary>Load static field address</summary>
public sealed partial class Ldsflda : SimpleInstruction
public sealed partial class LdsFlda : SimpleInstruction
{
public Ldsflda(FieldReference field) : base(OpCode.Ldsflda)
public LdsFlda(FieldReference field) : base(OpCode.LdsFlda)
{
this.field = field;
}
@ -822,14 +819,14 @@ namespace ICSharpCode.Decompiler.IL @@ -822,14 +819,14 @@ namespace ICSharpCode.Decompiler.IL
public FieldReference Field { get { return field; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdsflda(this);
return visitor.VisitLdsFlda(this);
}
}
/// <summary>Store value to static field</summary>
public sealed partial class Stsfld : UnaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
public sealed partial class StsFld : UnaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
public Stsfld(ILInstruction argument, FieldReference field) : base(OpCode.Stsfld, argument)
public StsFld(ILInstruction argument, FieldReference field) : base(OpCode.StsFld, argument)
{
this.field = field;
}
@ -847,7 +844,7 @@ namespace ICSharpCode.Decompiler.IL @@ -847,7 +844,7 @@ namespace ICSharpCode.Decompiler.IL
public FieldReference Field { get { return field; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitStsfld(this);
return visitor.VisitStsFld(this);
}
}
@ -869,9 +866,9 @@ namespace ICSharpCode.Decompiler.IL @@ -869,9 +866,9 @@ namespace ICSharpCode.Decompiler.IL
}
/// <summary>Indirect load (ref/pointer dereference).</summary>
public sealed partial class LdInd : UnaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
public sealed partial class LdObj : UnaryInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
public LdInd(ILInstruction argument, TypeReference type) : base(OpCode.LdInd, argument)
public LdObj(ILInstruction argument, TypeReference type) : base(OpCode.LdObj, argument)
{
this.type = type;
}
@ -889,7 +886,7 @@ namespace ICSharpCode.Decompiler.IL @@ -889,7 +886,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return type.GetStackType(); } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdInd(this);
return visitor.VisitLdObj(this);
}
}
@ -1038,11 +1035,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1038,11 +1035,11 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitConditionalBranch(ConditionalBranch inst)
protected internal virtual T VisitBranch(Branch inst)
{
return Default(inst);
}
protected internal virtual T VisitBranch(Branch inst)
protected internal virtual T VisitIfInstruction(IfInstruction inst)
{
return Default(inst);
}
@ -1078,7 +1075,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1078,7 +1075,7 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitCkFinite(CkFinite inst)
protected internal virtual T VisitCkfinite(Ckfinite inst)
{
return Default(inst);
}
@ -1130,27 +1127,27 @@ namespace ICSharpCode.Decompiler.IL @@ -1130,27 +1127,27 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitLdfld(Ldfld inst)
protected internal virtual T VisitLdFld(LdFld inst)
{
return Default(inst);
}
protected internal virtual T VisitLdflda(Ldflda inst)
protected internal virtual T VisitLdFlda(LdFlda inst)
{
return Default(inst);
}
protected internal virtual T VisitStfld(Stfld inst)
protected internal virtual T VisitStFld(StFld inst)
{
return Default(inst);
}
protected internal virtual T VisitLdsfld(Ldsfld inst)
protected internal virtual T VisitLdsFld(LdsFld inst)
{
return Default(inst);
}
protected internal virtual T VisitLdsflda(Ldsflda inst)
protected internal virtual T VisitLdsFlda(LdsFlda inst)
{
return Default(inst);
}
protected internal virtual T VisitStsfld(Stsfld inst)
protected internal virtual T VisitStsFld(StsFld inst)
{
return Default(inst);
}
@ -1158,7 +1155,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1158,7 +1155,7 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitLdInd(LdInd inst)
protected internal virtual T VisitLdObj(LdObj inst)
{
return Default(inst);
}
@ -1231,5 +1228,63 @@ namespace ICSharpCode.Decompiler.IL @@ -1231,5 +1228,63 @@ namespace ICSharpCode.Decompiler.IL
}
}
}
partial class InstructionOutputExtensions
{
static readonly string[] originalOpCodeNames = {
"nop",
"pop",
"peek",
"void",
"BlockContainer",
"Block",
"logic.not",
"add",
"sub",
"mul",
"div",
"rem",
"bit.and",
"bit.or",
"bit.xor",
"bit.not",
"arglist",
"br",
"if",
"debug.break",
"ceq",
"cgt",
"cgt.un",
"clt",
"clt.un",
"call",
"callvirt",
"ckfinite",
"conv",
"ldloc",
"ldloca",
"stloc",
"ldstr",
"ldc.i4",
"ldc.i8",
"ldc.f",
"ldnull",
"ret",
"shl",
"shr",
"ldfld",
"ldflda",
"stfld",
"ldsfld",
"ldsflda",
"stsfld",
"isinst",
"ldobj",
"unbox.any",
"newobj",
"throw",
"ldlen",
};
}
}

186
ICSharpCode.Decompiler/IL/Instructions.tt

@ -24,98 +24,101 @@ @@ -24,98 +24,101 @@
<#@ output extension=".cs" #>
<#
OpCode[] opCodes = {
new OpCode("Nop", "No operation. Takes 0 arguments and returns void.",
new OpCode("nop", "No operation. Takes 0 arguments and returns void.",
VoidResult, NoArguments),
new OpCode("Pop", "Pops the top of the evaluation stack and returns the value.",
new OpCode("pop", "Pops the top of the evaluation stack and returns the value.",
NoArguments, ResultTypeParam),
new OpCode("Peek", "Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.",
new OpCode("peek", "Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.",
Peeking, NoArguments, ResultTypeParam),
new OpCode("Void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.",
new OpCode("void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.",
VoidResult, Unary),
new OpCode("BlockContainer", "A container of IL blocks.", VoidResult, CustomConstructor),
new OpCode("Block", "A block of IL instructions.", CustomConstructor),
new OpCode("LogicNot", "Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).",
new OpCode("logic.not", "Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).",
ResultType("I4"), Unary),
new OpCode("Add", "Adds two numbers.", BinaryNumeric),
new OpCode("Sub", "Subtracts two numbers", BinaryNumeric),
new OpCode("Mul", "Multiplies two numbers", BinaryNumeric),
new OpCode("Div", "Divides two numbers", BinaryNumeric, MayThrow),
new OpCode("Rem", "Division remainder", BinaryNumeric, MayThrow),
new OpCode("BitAnd", "Bitwise AND", BinaryNumeric),
new OpCode("BitOr", "Bitwise OR", BinaryNumeric),
new OpCode("BitXor", "Bitwise XOR", BinaryNumeric),
new OpCode("BitNot", "Bitwise NOT", Unary),
new OpCode("Arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
new OpCode("ConditionalBranch", "<c>if (condition) goto target;</c>.",
BranchInstruction, CustomConstructor, CustomComputeFlags, MayBranch, VoidResult),
new OpCode("Branch", "<c>goto target;</c>.",
BranchInstruction, UnconditionalBranch, MayBranch),
new OpCode("DebugBreak", "Breakpoint instruction",
new OpCode("add", "Adds two numbers.", BinaryNumeric),
new OpCode("sub", "Subtracts two numbers", BinaryNumeric),
new OpCode("mul", "Multiplies two numbers", BinaryNumeric),
new OpCode("div", "Divides two numbers", BinaryNumeric, MayThrow),
new OpCode("rem", "Division remainder", BinaryNumeric, MayThrow),
new OpCode("bit.and", "Bitwise AND", BinaryNumeric),
new OpCode("bit.or", "Bitwise OR", BinaryNumeric),
new OpCode("bit.xor", "Bitwise XOR", BinaryNumeric),
new OpCode("bit.not", "Bitwise NOT", Unary),
new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
//new OpCode("ConditionalBranch", "<c>if (condition) goto target;</c>.",
// BranchInstruction, CustomConstructor, CustomComputeFlags, MayBranch, VoidResult),
new OpCode("br", "Unconditional branch. <c>goto target;</c>",
CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch),
new OpCode("if", "If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c>",
CustomClassName("IfInstruction"), CustomConstructor),
new OpCode("debug.break", "Breakpoint instruction",
NoArguments, VoidResult, SideEffect),
new OpCode("Ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.",
new OpCode("ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.",
BinaryComparison),
new OpCode("Cgt", "Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.",
new OpCode("cgt", "Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.",
BinaryComparison),
new OpCode("Cgt_Un", "Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.",
new OpCode("cgt.un", "Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.",
CustomClassName("Cgt_Un"), BinaryComparison),
new OpCode("clt", "Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.",
BinaryComparison),
new OpCode("Clt", "Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.",
BinaryComparison),
new OpCode("Clt_Un", "Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.",
BinaryComparison),
new OpCode("Call", "Non-virtual method call.", Call),
new OpCode("CallVirt", "Virtual method call.", Call),
new OpCode("CkFinite", "Checks that the float on top of the stack is not NaN or infinite.",
new OpCode("clt.un", "Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.",
CustomClassName("Clt_Un"), BinaryComparison),
new OpCode("call", "Non-virtual method call.", Call),
new OpCode("callvirt", "Virtual method call.",
CustomClassName("CallVirt"), Call),
new OpCode("ckfinite", "Checks that the float on top of the stack is not NaN or infinite.",
Peeking, NoArguments, MayThrow, VoidResult),
new OpCode("Conv", "Numeric cast.",
new OpCode("conv", "Numeric cast.",
Unary, CustomConstructor),
new OpCode("LdLoc", "Loads the value of a local variable. (ldarg/ldloc)",
NoArguments, HasVariableOperand, ResultType("variable.Type.GetStackType()")),
new OpCode("LdLoca", "Loads the address of a local variable. (ldarga/ldloca)",
NoArguments, ResultType("Ref"), HasVariableOperand),
new OpCode("StLoc", "Stores a value into a local variable. (starg/stloc)",
Unary, VoidResult, HasVariableOperand),
new OpCode("LdStr", "Loads a constant string.",
LoadConstant("string"), ResultType("O")),
new OpCode("LdcI4", "Loads a constant 32-bit integer.",
new OpCode("ldloc", "Loads the value of a local variable. (ldarg/ldloc)",
CustomClassName("LdLoc"), NoArguments, HasVariableOperand, ResultType("variable.Type.GetStackType()")),
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"), Unary, VoidResult, HasVariableOperand),
new OpCode("ldstr", "Loads a constant string.",
CustomClassName("LdStr"), LoadConstant("string"), ResultType("O")),
new OpCode("ldc.i4", "Loads a constant 32-bit integer.",
LoadConstant("int"), ResultType("I4")),
new OpCode("LdcI8", "Loads a constant 64-bit integer.",
new OpCode("ldc.i8", "Loads a constant 64-bit integer.",
LoadConstant("long"), ResultType("I8")),
new OpCode("LdcF", "Loads a constant floating-point number.",
new OpCode("ldc.f", "Loads a constant floating-point number.",
LoadConstant("double"), ResultType("F")),
new OpCode("LdNull", "Loads the null reference.",
NoArguments, ResultType("O")),
new OpCode("Return", "Returns from the current method or lambda.",
CustomConstructor, MayBranch, UnconditionalBranch),
new OpCode("Shl", "Shift left", BinaryNumeric),
new OpCode("Shr", "Shift right", BinaryNumeric),
new OpCode("ldnull", "Loads the null reference.",
CustomClassName("LdNull"), NoArguments, ResultType("O")),
new OpCode("ret", "Returns from the current method or lambda.",
CustomClassName("Return"), CustomConstructor, MayBranch, UnconditionalBranch),
new OpCode("shl", "Shift left", BinaryNumeric),
new OpCode("shr", "Shift right", BinaryNumeric),
new OpCode("Ldfld", "Load instance field",
Unary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow,
new OpCode("ldfld", "Load instance field",
CustomClassName("LdFld"), Unary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow,
HasFieldOperand, ResultType("field.FieldType.GetStackType()")),
new OpCode("Ldflda", "Load address of instance field",
Unary, MayThrow, HasFieldOperand, ResultType("Ref")),
new OpCode("Stfld", "Store value to instance field",
Binary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, VoidResult, HasFieldOperand),
new OpCode("Ldsfld", "Load static field",
NoArguments, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix,
new OpCode("ldflda", "Load address of instance field",
CustomClassName("LdFlda"), Unary, MayThrow, HasFieldOperand, ResultType("Ref")),
new OpCode("stfld", "Store value to instance field",
CustomClassName("StFld"), Binary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, VoidResult, HasFieldOperand),
new OpCode("ldsfld", "Load static field",
CustomClassName("LdsFld"), NoArguments, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix,
HasFieldOperand, ResultType("field.FieldType.GetStackType()")),
new OpCode("Ldsflda", "Load static field address",
NoArguments, ResultType("Ref"), HasFieldOperand),
new OpCode("Stsfld", "Store value to static field",
Unary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, VoidResult, HasFieldOperand),
new OpCode("ldsflda", "Load static field address",
CustomClassName("LdsFlda"), NoArguments, ResultType("Ref"), HasFieldOperand),
new OpCode("stsfld", "Store value to static field",
CustomClassName("StsFld"), Unary, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, VoidResult, HasFieldOperand),
new OpCode("IsInst", "Test if object is instance of class or interface.",
Unary, HasTypeOperand, ResultType("type.GetStackType()")),
new OpCode("LdInd", "Indirect load (ref/pointer dereference).",
Unary, HasTypeOperand, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("type.GetStackType()")),
new OpCode("UnboxAny", "Unbox a value.",
new OpCode("isinst", "Test if object is instance of class or interface.",
CustomClassName("IsInst"), Unary, HasTypeOperand, ResultType("type.GetStackType()")),
new OpCode("ldobj", "Indirect load (ref/pointer dereference).",
CustomClassName("LdObj"), Unary, HasTypeOperand, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("type.GetStackType()")),
new OpCode("unbox.any", "Unbox a value.",
Unary, HasTypeOperand, MemoryAccess, MayThrow, ResultType("type.GetStackType()")),
new OpCode("NewObj", "Creates an object instance and calls the constructor.",
Call, ResultType("O")),
new OpCode("Throw", "Throws an exception.",
new OpCode("newobj", "Creates an object instance and calls the constructor.",
CustomClassName("NewObj"), Call, ResultType("O")),
new OpCode("throw", "Throws an exception.",
Unary, MayThrow, UnconditionalBranch),
new OpCode("LdLen", "Returns the length of an array as 'native unsigned int'.",
Unary, MayThrow, ResultType("I")),
new OpCode("ldlen", "Returns the length of an array as 'native unsigned int'.",
CustomClassName("LdLen"), Unary, MayThrow, ResultType("I")),
};
@ -204,6 +207,15 @@ namespace ICSharpCode.Decompiler.IL @@ -204,6 +207,15 @@ namespace ICSharpCode.Decompiler.IL
}
}
}
partial class InstructionOutputExtensions
{
static readonly string[] originalOpCodeNames = {
<# foreach (OpCode opCode in opCodes) { #>
"<#=opCode.OriginalName#>",
<# } #>
};
}
}
<#+
@ -221,16 +233,29 @@ namespace ICSharpCode.Decompiler.IL @@ -221,16 +233,29 @@ namespace ICSharpCode.Decompiler.IL
}
class OpCode {
public readonly string Name;
public readonly string OriginalName;
public string Name;
public readonly string Description;
public OpCode(string name, string description, params Action<OpCode>[] traits)
public OpCode(string originalName, string description, params Action<OpCode>[] traits)
{
this.Name = name;
this.OriginalName = originalName;
StringBuilder name = new StringBuilder();
bool nextUpper = true;
foreach (char c in originalName) {
if (c == '.')
nextUpper = true;
else if (nextUpper) {
name.Append(char.ToUpper(c));
nextUpper = false;
} else
name.Append(c);
}
this.Name = name.ToString();
this.Description = description;
this.BaseConstructorArguments.Add("OpCode." + name);
foreach (var trait in traits)
trait(this);
this.BaseConstructorArguments.Insert(0, "OpCode." + this.Name);
}
public bool GenerateConstructor = true;
@ -246,6 +271,13 @@ namespace ICSharpCode.Decompiler.IL @@ -246,6 +271,13 @@ namespace ICSharpCode.Decompiler.IL
public bool GenerateComputeFlags = true;
}
static Action<OpCode> CustomClassName(string name)
{
return opCode => {
opCode.Name = name;
};
}
static Action<OpCode> CustomConstructor = opCode => {
opCode.GenerateConstructor = false;
};
@ -342,12 +374,6 @@ namespace ICSharpCode.Decompiler.IL @@ -342,12 +374,6 @@ namespace ICSharpCode.Decompiler.IL
opCode.BaseClass = "BinaryComparisonInstruction";
};
static Action<OpCode> BranchInstruction = opCode => {
opCode.BaseClass = "BranchInstruction";
opCode.ConstructorParameters.Add("int targetILOffset");
opCode.BaseConstructorArguments.Add("targetILOffset");
};
// SideEffect trait: the instruction has a non-local side effect
static Action<OpCode> SideEffect = HasFlag("InstructionFlags.SideEffect");
static Action<OpCode> MemoryAccess = SideEffect;

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

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
partial class Branch : SimpleInstruction
{
public readonly int TargetILOffset;
/// <summary>
/// Pops the specified number of arguments from the evaluation stack during the branching operation.
/// Note that the Branch instruction does not set InstructionFlags.MayPop -- the pop instead is considered
/// to happen after the branch was taken.
/// </summary>
public int PopCount;
public Branch(int targetILOffset) : base(OpCode.Branch)
{
this.TargetILOffset = targetILOffset;
}
public string TargetLabel {
get { return CecilExtensions.OffsetToString(TargetILOffset); }
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
output.WriteReference(TargetLabel, TargetILOffset, isLocal: true);
if (PopCount != 0) {
output.Write(" (pop ");
output.Write(PopCount.ToString());
output.Write(')');
}
}
}
}

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

@ -1,156 +0,0 @@ @@ -1,156 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
/// <summary>
/// Base class for unconditional and conditional branches.
/// </summary>
public abstract class BranchInstruction : ILInstruction
{
public readonly int TargetILOffset;
protected BranchInstruction(OpCode opCode, int targetILOffset) : base(opCode)
{
this.TargetILOffset = targetILOffset;
}
public string TargetLabel {
get { return CecilExtensions.OffsetToString(TargetILOffset); }
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode.ToString());
output.Write(' ');
output.WriteReference(TargetLabel, TargetILOffset, isLocal: true);
}
}
partial class Branch
{
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
return initial;
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
finished = true;
return this;
}
}
partial class ConditionalBranch
{
ILInstruction condition;
public ConditionalBranch(ILInstruction condition, int targetILOffset) : base(OpCode.ConditionalBranch, targetILOffset)
{
this.Condition = condition;
}
public ILInstruction Condition {
get {
return condition;
}
set {
ValidateArgument(value);
SetChildInstruction(ref condition, value);
}
}
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
return func(initial, condition.AcceptVisitor(visitor));
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
this.Condition = condition.AcceptVisitor(visitor);
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
this.Condition = condition.Inline(flagsBefore, instructionStack, out finished);
return this;
}
protected override InstructionFlags ComputeFlags()
{
return condition.Flags | InstructionFlags.MayBranch;
}
}
/*
/// <summary>
/// Special instruction for unresolved branches.
/// Created by ILReader phase, replaced with TODO when building basic blocks.
/// </summary>
class ConditionalBranch(public ILInstruction Condition, int targetILOffset) : Branch(OpCode.ConditionalBranch, targetILOffset)
{
public override bool IsPeeking { get { return Condition.IsPeeking; } }
public override void WriteTo(ITextOutput output)
{
base.WriteTo(output);
output.Write('(');
Condition.WriteTo(output);
output.Write(')');
}
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc)
{
Condition = transformFunc(Condition);
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
Condition = Condition.Inline(flagsBefore, instructionStack, out finished);
return this;
}
public override InstructionFlags Flags
{
get { return InstructionFlags.MayJump | Condition.Flags; }
}
}
class ReturnVoidInstruction() : SimpleInstruction(OpCode.Ret)
{
public override bool IsEndReachable { get { return false; } }
public override InstructionFlags Flags
{
get { return InstructionFlags.MayJump; }
}
}
class ReturnInstruction() : UnaryInstruction(OpCode.Ret)
{
public override bool IsEndReachable { get { return false; } }
public override InstructionFlags Flags
{
get { return InstructionFlags.MayJump | Operand.Flags; }
}
}
class ThrowInstruction() : UnaryInstruction(OpCode.Throw)
{
public override bool IsEndReachable { get { return false; } }
public override InstructionFlags Flags
{
get { return InstructionFlags.MayJump | Operand.Flags; }
}
}*/
}

116
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -0,0 +1,116 @@ @@ -0,0 +1,116 @@
// Copyright (c) 2014 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.IL
{
partial class IfInstruction : ILInstruction
{
ILInstruction condition;
ILInstruction trueInst;
ILInstruction falseInst;
public IfInstruction(ILInstruction condition, ILInstruction trueInst, ILInstruction falseInst = null) : base(OpCode.IfInstruction)
{
this.Condition = condition;
this.TrueInst = trueInst;
this.FalseInst = falseInst ?? new Nop();
}
public ILInstruction Condition {
get { return condition; }
set {
ValidateArgument(value);
SetChildInstruction(ref condition, value);
}
}
public ILInstruction TrueInst {
get { return trueInst; }
set {
if (value == null)
throw new ArgumentNullException();
SetChildInstruction(ref trueInst, value);
}
}
public ILInstruction FalseInst {
get { return falseInst; }
set {
if (value == null)
throw new ArgumentNullException();
SetChildInstruction(ref falseInst, value);
}
}
public override StackType ResultType {
get {
return trueInst.ResultType;
}
}
public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate value = initial;
value = func(value, condition.AcceptVisitor(visitor));
value = func(value, trueInst.AcceptVisitor(visitor));
value = func(value, falseInst.AcceptVisitor(visitor));
return value;
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
this.Condition = condition.AcceptVisitor(visitor);
this.TrueInst = trueInst.AcceptVisitor(visitor);
this.FalseInst = falseInst.AcceptVisitor(visitor);
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
this.Condition = condition.Inline(flagsBefore, instructionStack, out finished);
// don't continue inlining if this instruction still contains peek/pop instructions
if (HasFlag(InstructionFlags.MayPeek | InstructionFlags.MayPop))
finished = false;
return this;
}
protected override InstructionFlags ComputeFlags()
{
// the endpoint of the 'if' is only unreachable if both branches have an unreachable endpoint
const InstructionFlags combineWithAnd = InstructionFlags.EndPointUnreachable;
InstructionFlags trueFlags = trueInst.Flags;
InstructionFlags falseFlags = falseInst.Flags;
return condition.Flags | (trueFlags & falseFlags) | ((trueFlags | falseFlags) & ~combineWithAnd);
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(" (");
condition.WriteTo(output);
output.Write(") ");
trueInst.WriteTo(output);
if (falseInst.OpCode != OpCode.Nop) {
output.Write(" else ");
falseInst.WriteTo(output);
}
}
}
}
Loading…
Cancel
Save