Browse Source

Merge Return instruction into Leave.

pull/863/head
Siegfried Pammer 8 years ago
parent
commit
206cdecf30
  1. 13
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  2. 7
      ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs
  3. 8
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  4. 20
      ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowGraph.cs
  5. 18
      ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs
  6. 5
      ICSharpCode.Decompiler/IL/ControlFlow/ExitPoints.cs
  7. 31
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  8. 3
      ICSharpCode.Decompiler/IL/ILReader.cs
  9. 172
      ICSharpCode.Decompiler/IL/Instructions.cs
  10. 6
      ICSharpCode.Decompiler/IL/Instructions.tt
  11. 10
      ICSharpCode.Decompiler/IL/Instructions/Leave.cs
  12. 30
      ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs
  13. 2
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  14. 2
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

13
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -161,7 +161,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -161,7 +161,10 @@ namespace ICSharpCode.Decompiler.CSharp
if (inst.IsLeavingFunction) {
if (currentFunction.IsIterator)
return new YieldBreakStatement();
else
else if (!inst.Value.MatchNop()) {
IType targetType = currentFunction.IsAsync ? currentFunction.AsyncReturnType : currentMethod.ReturnType;
return new ReturnStatement(exprBuilder.Translate(inst.Value).ConvertTo(targetType, exprBuilder, allowImplicitConversion: true));
} else
return new ReturnStatement();
}
string label;
@ -181,12 +184,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -181,12 +184,6 @@ namespace ICSharpCode.Decompiler.CSharp
{
return new ThrowStatement();
}
protected internal override Statement VisitReturn(Return inst)
{
IType targetType = currentFunction.IsAsync ? currentFunction.AsyncReturnType : currentMethod.ReturnType;
return new ReturnStatement(exprBuilder.Translate(inst.Value).ConvertTo(targetType, exprBuilder, allowImplicitConversion: true));
}
protected internal override Statement VisitYieldReturn(YieldReturn inst)
{
@ -420,6 +417,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -420,6 +417,8 @@ namespace ICSharpCode.Decompiler.CSharp
static bool IsFinalLeave(Leave leave)
{
if (!leave.Value.MatchNop())
return false;
Block block = (Block)leave.Parent;
if (leave.ChildIndex != block.Instructions.Count - 1 || block.FinalInstruction.OpCode != OpCode.Nop)
return false;

7
ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs

@ -416,6 +416,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -416,6 +416,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
protected internal override void VisitLeave(Leave inst)
{
inst.Value.AcceptVisitor(this);
State targetState;
if (stateOnLeave.TryGetValue(inst.TargetContainer, out targetState)) {
targetState.JoinWith(state);
@ -428,12 +429,6 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -428,12 +429,6 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
MarkUnreachable();
}
protected internal override void VisitReturn(Return inst)
{
inst.Value.AcceptVisitor(this);
MarkUnreachable();
}
protected internal override void VisitThrow(Throw inst)
{
inst.Argument.AcceptVisitor(this);

8
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -447,10 +447,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -447,10 +447,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
moveNextFunction.ReleaseRef();
foreach (var branch in function.Descendants.OfType<Branch>()) {
if (branch.TargetBlock == setResultAndExitBlock) {
if (resultVar != null)
branch.ReplaceWith(new Return(new LdLoc(resultVar)) { ILRange = branch.ILRange });
else
branch.ReplaceWith(new Leave((BlockContainer)function.Body) { ILRange = branch.ILRange });
branch.ReplaceWith(new Leave((BlockContainer)function.Body) {
Value = resultVar == null ? (ILInstruction)new Nop() : new LdLoc(resultVar),
ILRange = branch.ILRange
});
}
}
function.Variables.AddRange(function.Descendants.OfType<IInstructionWithVariableOperand>().Select(inst => inst.Variable).Distinct());

20
ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowGraph.cs

@ -100,9 +100,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -100,9 +100,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// Leave instructions (like other exits out of the container)
// are ignored for the CFG and dominance,
// but is relevant for HasReachableExit().
// However, a 'leave' that exits the whole function represents a void return,
// and is not considered a reachable exit (just like non-void returns).
if (!(leave.TargetContainer.Parent is ILFunction)) {
// However, a 'leave' that exits the whole function represents a return,
// and is not considered a reachable exit.
if (!leave.IsLeavingFunction) {
nodeHasDirectExitOutOfContainer.Set(i);
}
}
@ -131,20 +131,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -131,20 +131,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return leaving;
}
bool LeavesCurrentBlockContainer(Block block)
{
foreach (var node in block.Descendants) {
if (node is Branch branch && !branch.TargetBlock.IsDescendantOf(container)) {
// control flow that isn't internal to the block container
return true;
}
if (node is Leave leave && !leave.TargetContainer.IsDescendantOf(block)) {
return true;
}
}
return false;
}
/// <summary>
/// Gets the ControlFlowNode for the block.
///

18
ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs

@ -64,13 +64,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -64,13 +64,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// (where 'v' has no other uses)
// Simplify these to a simple `ret(<inst>)` so that they match the release build version.
//
if (block.Instructions.Count == 2 && block.Instructions[1].OpCode == OpCode.Return) {
Return ret = (Return)block.Instructions[1];
ILVariable v;
ILInstruction inst;
if (ret.Value.MatchLdLoc(out v)
&& v.IsSingleDefinition && v.LoadCount == 1 && block.Instructions[0].MatchStLoc(v, out inst))
{
if (block.Instructions.Count == 2 && block.Instructions[1].MatchReturn(out ILInstruction value)) {
var ret = (Leave)block.Instructions[1];
if (value.MatchLdLoc(out ILVariable v)
&& v.IsSingleDefinition && v.LoadCount == 1 && block.Instructions[0].MatchStLoc(v, out ILInstruction inst)) {
context.Step("Inline variable in return block", block);
inst.AddILRange(ret.Value.ILRange);
inst.AddILRange(block.Instructions[0].ILRange);
@ -119,11 +116,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -119,11 +116,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
blocksToAdd.Add((localContainer, blockCopy));
branch.TargetBlock = blockCopy;
}
} else if (targetBlock.Instructions.Count == 1 && targetBlock.Instructions[0].OpCode == OpCode.Leave) {
} else if (targetBlock.Instructions.Count == 1 && targetBlock.Instructions[0] is Leave leave && leave.Value.MatchNop()) {
context.Step("Replace branch to leave with leave", branch);
// Replace branches to 'leave' instruction with the leave instruction
Leave leave = (Leave)targetBlock.Instructions[0];
branch.ReplaceWith(new Leave(leave.TargetContainer) { ILRange = branch.ILRange });
branch.ReplaceWith(leave.Clone());
}
if (targetBlock.IncomingEdgeCount == 0)
targetBlock.Instructions.Clear(); // mark the block for deletion
@ -154,7 +150,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -154,7 +150,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
var targetBlock = branch.TargetBlock;
if (targetBlock.Instructions.Count != 1 || targetBlock.FinalInstruction.OpCode != OpCode.Nop)
return false;
return targetBlock.Instructions[0] is Return ret && ret.Value is LdLoc;
return targetBlock.Instructions[0].MatchReturn(out var value) && value is LdLoc;
}
static bool CombineBlockWithNextBlock(BlockContainer container, Block block)

5
ICSharpCode.Decompiler/IL/ControlFlow/ExitPoints.cs

@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
case OpCode.Leave:
Leave leave1 = (Leave)exit1;
Leave leave2 = (Leave)exit2;
return leave1.TargetContainer == leave2.TargetContainer;
return leave1.TargetContainer == leave2.TargetContainer && leave1.Value.MatchNop() && leave2.Value.MatchNop();
default:
return false;
}
@ -192,6 +192,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -192,6 +192,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
protected internal override void VisitLeave(Leave inst)
{
base.VisitLeave(inst);
if (!inst.Value.MatchNop())
return;
HandleExit(inst);
}
}

31
ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

@ -747,23 +747,22 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -747,23 +747,22 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
}
break;
case Leave leave:
if (leave.TargetContainer == oldBody) {
leave.TargetContainer = newBody;
}
break;
case Return ret:
ILInstruction value = ret.Value;
if (value.MatchLdLoc(out var v) && v.IsSingleDefinition
&& v.StoreInstructions.SingleOrDefault() is StLoc stloc)
{
returnStores.Add(stloc);
value = stloc.Value;
}
if (value.MatchLdcI4(0)) {
// yield break
ret.ReplaceWith(new Leave(newBody) { ILRange = ret.ILRange });
if (leave.MatchReturn(out var value)) {
if (value.MatchLdLoc(out var v) && v.IsSingleDefinition
&& v.StoreInstructions.SingleOrDefault() is StLoc stloc) {
returnStores.Add(stloc);
value = stloc.Value;
}
if (value.MatchLdcI4(0)) {
// yield break
leave.ReplaceWith(new Leave(newBody) { ILRange = leave.ILRange });
} else {
leave.ReplaceWith(new InvalidBranch("Unexpected return in MoveNext()") { ILRange = leave.ILRange });
}
} else {
ret.ReplaceWith(new InvalidBranch("Unexpected return in MoveNext()") { ILRange = ret.ILRange });
if (leave.TargetContainer == oldBody) {
leave.TargetContainer = newBody;
}
}
break;
}

3
ICSharpCode.Decompiler/IL/ILReader.cs

@ -526,6 +526,7 @@ namespace ICSharpCode.Decompiler.IL @@ -526,6 +526,7 @@ namespace ICSharpCode.Decompiler.IL
case Cil.Code.Dup:
return Push(Peek());
case Cil.Code.Endfilter:
return new Leave(null) { Value = Pop() };
case Cil.Code.Endfinally:
return new Leave(null);
case Cil.Code.Initblk:
@ -942,7 +943,7 @@ namespace ICSharpCode.Decompiler.IL @@ -942,7 +943,7 @@ namespace ICSharpCode.Decompiler.IL
if (methodReturnStackType == StackType.Void)
return new IL.Leave(mainContainer);
else
return new IL.Return(Pop(methodReturnStackType));
return new IL.Leave(mainContainer) { Value = Pop(methodReturnStackType) };
}
private ILInstruction DecodeLdstr()

172
ICSharpCode.Decompiler/IL/Instructions.cs

@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.IL @@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.IL
Arglist,
/// <summary>Unconditional branch. <c>goto target;</c></summary>
Branch,
/// <summary>Unconditional branch to end of block container. <c>goto container_end;</c>, often <c>break;</c></summary>
/// <summary>Unconditional branch to end of block container. Return is represented using IsLeavingFunction and an (optional) return value. The block container evaluates to the value produced by the argument of the leave instruction.</summary>
Leave,
/// <summary>If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c></summary>
IfInstruction,
@ -115,8 +115,6 @@ namespace ICSharpCode.Decompiler.IL @@ -115,8 +115,6 @@ namespace ICSharpCode.Decompiler.IL
LdMemberToken,
/// <summary>Allocates space in the stack frame</summary>
LocAlloc,
/// <summary>Returns from the current method or lambda. Only used when returning a value; void returns are represented using a 'leave' instruction.</summary>
Return,
/// <summary>Load address of instance field</summary>
LdFlda,
/// <summary>Load static field address</summary>
@ -1060,9 +1058,56 @@ namespace ICSharpCode.Decompiler.IL @@ -1060,9 +1058,56 @@ namespace ICSharpCode.Decompiler.IL
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Unconditional branch to end of block container. <c>goto container_end;</c>, often <c>break;</c></summary>
public sealed partial class Leave : SimpleInstruction
/// <summary>Unconditional branch to end of block container. Return is represented using IsLeavingFunction and an (optional) return value. The block container evaluates to the value produced by the argument of the leave instruction.</summary>
public sealed partial class Leave : ILInstruction
{
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;
public ILInstruction Value {
get { return this.value; }
set {
ValidateChild(value);
SetChildInstruction(ref this.value, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ValueSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (Leave)ShallowClone();
clone.Value = this.value.Clone();
return clone;
}
public override StackType ResultType { get { return StackType.Void; } }
public override void AcceptVisitor(ILVisitor visitor)
{
@ -1079,7 +1124,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1079,7 +1124,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Leave;
return o != null && this.TargetContainer == o.TargetContainer;
return o != null && this.value.PerformMatch(o.value, ref match) && this.TargetContainer == o.TargetContainer;
}
}
}
@ -2538,98 +2583,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2538,98 +2583,6 @@ namespace ICSharpCode.Decompiler.IL
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Returns from the current method or lambda. Only used when returning a value; void returns are represented using a 'leave' instruction.</summary>
public sealed partial class Return : ILInstruction
{
public Return(ILInstruction value) : base(OpCode.Return)
{
this.Value = value;
}
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;
public ILInstruction Value {
get { return this.value; }
set {
ValidateChild(value);
SetChildInstruction(ref this.value, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ValueSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (Return)ShallowClone();
clone.Value = this.value.Clone();
return clone;
}
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags()
{
return value.Flags | InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
this.value.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitReturn(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitReturn(this);
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
return visitor.VisitReturn(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Return;
return o != null && this.value.PerformMatch(o.value, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Load address of instance field</summary>
public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand
@ -4319,10 +4272,6 @@ namespace ICSharpCode.Decompiler.IL @@ -4319,10 +4272,6 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitReturn(Return inst)
{
Default(inst);
}
protected internal virtual void VisitLdFlda(LdFlda inst)
{
Default(inst);
@ -4597,10 +4546,6 @@ namespace ICSharpCode.Decompiler.IL @@ -4597,10 +4546,6 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitReturn(Return inst)
{
return Default(inst);
}
protected internal virtual T VisitLdFlda(LdFlda inst)
{
return Default(inst);
@ -4875,10 +4820,6 @@ namespace ICSharpCode.Decompiler.IL @@ -4875,10 +4820,6 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
protected internal virtual T VisitReturn(Return inst, C context)
{
return Default(inst, context);
}
protected internal virtual T VisitLdFlda(LdFlda inst, C context)
{
return Default(inst, context);
@ -5019,7 +4960,6 @@ namespace ICSharpCode.Decompiler.IL @@ -5019,7 +4960,6 @@ namespace ICSharpCode.Decompiler.IL
"ldtypetoken",
"ldmembertoken",
"localloc",
"ret",
"ldflda",
"ldsflda",
"castclass",
@ -5299,16 +5239,6 @@ namespace ICSharpCode.Decompiler.IL @@ -5299,16 +5239,6 @@ namespace ICSharpCode.Decompiler.IL
argument = default(ILInstruction);
return false;
}
public bool MatchReturn(out ILInstruction value)
{
var inst = this as Return;
if (inst != null) {
value = inst.Value;
return true;
}
value = default(ILInstruction);
return false;
}
public bool MatchLdFlda(out ILInstruction target, out IField field)
{
var inst = this as LdFlda;

6
ICSharpCode.Decompiler/IL/Instructions.tt

@ -77,8 +77,8 @@ @@ -77,8 +77,8 @@
new OpCode("br", "Unconditional branch. <c>goto target;</c>",
CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags,
MatchCondition("this.TargetBlock == o.TargetBlock")),
new OpCode("leave", "Unconditional branch to end of block container. <c>goto container_end;</c>, often <c>break;</c>",
NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags,
new OpCode("leave", "Unconditional branch to end of block container. Return is represented using IsLeavingFunction and an (optional) return value. The block container evaluates to the value produced by the argument of the leave instruction.",
CustomConstructor, CustomArguments("value"), UnconditionalBranch, MayBranch, CustomWriteTo, CustomComputeFlags,
MatchCondition("this.TargetContainer == o.TargetContainer")),
new OpCode("if", "If statement / conditional expression. <c>if (condition) trueExpr else falseExpr</c>",
CustomClassName("IfInstruction"),
@ -164,8 +164,6 @@ @@ -164,8 +164,6 @@
CustomClassName("LdMemberToken"), NoArguments, HasMemberOperand, ResultType("O")),
new OpCode("localloc", "Allocates space in the stack frame",
CustomClassName("LocAlloc"), Unary, ResultType("I"), MayThrow),
new OpCode("ret", "Returns from the current method or lambda. Only used when returning a value; void returns are represented using a 'leave' instruction.",
CustomClassName("Return"), CustomArguments("value"), MayBranch, UnconditionalBranch),
new OpCode("ldflda", "Load address of instance field",
CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand, ResultType("Ref")),

10
ICSharpCode.Decompiler/IL/Instructions/Leave.cs

@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.IL @@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.IL
/// Phase-2 execution removes PopCount elements from the evaluation stack
/// and jumps to the target block.
/// </remarks>
partial class Leave : SimpleInstruction
partial class Leave : ILInstruction
{
BlockContainer targetContainer;
@ -39,11 +39,12 @@ namespace ICSharpCode.Decompiler.IL @@ -39,11 +39,12 @@ namespace ICSharpCode.Decompiler.IL
// Note: ILReader will create Leave instructions with targetContainer==null to represent 'endfinally',
// the targetContainer will then be filled in by BlockBuilder
this.targetContainer = targetContainer;
this.Value = new Nop();
}
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
return value.Flags | InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
public override InstructionFlags DirectFlags {
@ -78,7 +79,7 @@ namespace ICSharpCode.Decompiler.IL @@ -78,7 +79,7 @@ namespace ICSharpCode.Decompiler.IL
}
public string TargetLabel {
get { return targetContainer != null ? targetContainer.EntryPoint.Label : string.Empty; }
get { return targetContainer?.EntryPoint != null ? targetContainer.EntryPoint.Label : string.Empty; }
}
/// <summary>
@ -104,6 +105,9 @@ namespace ICSharpCode.Decompiler.IL @@ -104,6 +105,9 @@ namespace ICSharpCode.Decompiler.IL
if (targetContainer != null) {
output.Write(' ');
output.WriteReference(TargetLabel, targetContainer, isLocal: true);
output.Write(" (");
value.WriteTo(output);
output.Write(')');
}
}
}

30
ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs

@ -120,7 +120,18 @@ namespace ICSharpCode.Decompiler.IL @@ -120,7 +120,18 @@ namespace ICSharpCode.Decompiler.IL
array = null;
return false;
}
public bool MatchReturn(out ILInstruction value)
{
var inst = this as Leave;
if (inst != null && inst.IsLeavingFunction) {
value = inst.Value;
return true;
}
value = default(ILInstruction);
return false;
}
public bool MatchBranch(out Block targetBlock)
{
var inst = this as Branch;
@ -137,11 +148,24 @@ namespace ICSharpCode.Decompiler.IL @@ -137,11 +148,24 @@ namespace ICSharpCode.Decompiler.IL
var inst = this as Branch;
return inst != null && inst.TargetBlock == targetBlock;
}
public bool MatchLeave(out BlockContainer targetContainer, out ILInstruction value)
{
var inst = this as Leave;
if (inst != null) {
targetContainer = inst.TargetContainer;
value = inst.Value;
return true;
}
targetContainer = null;
value = null;
return false;
}
public bool MatchLeave(out BlockContainer targetContainer)
{
var inst = this as Leave;
if (inst != null) {
if (inst != null && inst.Value.MatchNop()) {
targetContainer = inst.TargetContainer;
return true;
}
@ -152,7 +176,7 @@ namespace ICSharpCode.Decompiler.IL @@ -152,7 +176,7 @@ namespace ICSharpCode.Decompiler.IL
public bool MatchLeave(BlockContainer targetContainer)
{
var inst = this as Leave;
return inst != null && inst.TargetContainer == targetContainer;
return inst != null && inst.TargetContainer == targetContainer && inst.Value.MatchNop();
}
public bool MatchIfInstruction(out ILInstruction condition, out ILInstruction trueInst, out ILInstruction falseInst)

2
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -259,7 +259,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -259,7 +259,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (p != null && !string.IsNullOrEmpty(p.Name))
return CleanUpVariableName(p.Name);
break;
case Return ret:
case Leave ret:
return "result";
}
return null;

2
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -272,7 +272,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -272,7 +272,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// decide based on the target into which we are inlining
var parent = loadInst.Parent;
switch (next.OpCode) {
case OpCode.Return:
case OpCode.Leave:
return parent == next;
case OpCode.IfInstruction:
while (parent.OpCode == OpCode.LogicNot) {

Loading…
Cancel
Save