Browse Source

Handle leave instructions in state-range analysis.

pull/2639/head
Siegfried Pammer 3 years ago
parent
commit
a4e2bd7f8f
  1. 6
      ICSharpCode.Decompiler/IL/ControlFlow/AwaitInFinallyTransform.cs
  2. 21
      ICSharpCode.Decompiler/IL/ControlFlow/StateRangeAnalysis.cs

6
ICSharpCode.Decompiler/IL/ControlFlow/AwaitInFinallyTransform.cs

@ -128,6 +128,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
StateRangeAnalysis sra = new StateRangeAnalysis(StateRangeAnalysisMode.AwaitInFinally, null, stateVariable);
sra.AssignStateRanges(noThrowBlock, Util.LongSet.Universe);
var mapping = sra.GetBlockStateSetMapping((BlockContainer)noThrowBlock.Parent);
var mappingForLeave = sra.GetBlockStateSetMappingForLeave();
context.StepStartGroup("Inline finally block with await", tryCatch.Handlers[0]);
var cfg = new ControlFlowGraph(container, context.CancellationToken);
@ -161,6 +162,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.Step($"branch to finally with state {value} => branch to state target " + targetBlock.Label, branch);
branch.TargetBlock = targetBlock;
}
else if (mappingForLeave.TryGetValue(value, out BlockContainer targetContainer))
{
context.Step($"branch to finally with state {value} => leave to state target " + targetContainer, branch);
branch.ReplaceWith(new Leave(targetContainer).WithILRange(branch));
}
else
{
context.Step("branch to finally => branch after finally", branch);

21
ICSharpCode.Decompiler/IL/ControlFlow/StateRangeAnalysis.cs

@ -61,6 +61,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
readonly SymbolicEvaluationContext evalContext;
readonly Dictionary<Block, LongSet> ranges = new Dictionary<Block, LongSet>();
readonly Dictionary<BlockContainer, LongSet>? rangesForLeave; // used only for AwaitInFinally
readonly internal Dictionary<IMethod, LongSet>? finallyMethodToStateRange; // used only for IteratorDispose
internal ILVariable? doFinallyBodies;
@ -74,6 +75,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
{
finallyMethodToStateRange = new Dictionary<IMethod, LongSet>();
}
if (mode == StateRangeAnalysisMode.AwaitInFinally)
{
rangesForLeave = new Dictionary<BlockContainer, LongSet>();
}
evalContext = new SymbolicEvaluationContext(stateField);
if (cachedStateVar != null)
@ -177,6 +182,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
case Branch br:
AddStateRange(br.TargetBlock, stateRange);
return LongSet.Empty;
case Leave leave when mode == StateRangeAnalysisMode.AwaitInFinally:
AddStateRangeForLeave(leave.TargetContainer, stateRange);
return LongSet.Empty;
case Nop nop:
return stateRange;
case StLoc stloc when stloc.Variable == doFinallyBodies || stloc.Variable == skipFinallyBodies:
@ -233,6 +241,15 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
ranges.Add(block, stateRange);
}
private void AddStateRangeForLeave(BlockContainer target, LongSet stateRange)
{
if (rangesForLeave!.TryGetValue(target, out var existingRange))
rangesForLeave[target] = stateRange.UnionWith(existingRange);
else
rangesForLeave.Add(target, stateRange);
}
/// <summary>
/// Gets a mapping from states to blocks.
///
@ -262,5 +279,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
}
}
}
public LongDict<BlockContainer> GetBlockStateSetMappingForLeave()
{
return LongDict.Create(rangesForLeave.Select(kv => (kv.Value, kv.Key)));
}
}
}
Loading…
Cancel
Save