mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
3.4 KiB
111 lines
3.4 KiB
using System.Collections.Generic; |
|
using System.Linq; |
|
using ICSharpCode.Decompiler.FlowAnalysis; |
|
using ICSharpCode.Decompiler.IL.ControlFlow; |
|
|
|
namespace ICSharpCode.Decompiler.IL.Transforms |
|
{ |
|
/// <summary> |
|
/// Per-block IL transform. |
|
/// </summary> |
|
public interface IBlockTransform |
|
{ |
|
void Run(Block block, BlockTransformContext context); |
|
} |
|
|
|
/// <summary> |
|
/// Parameter class holding various arguments for <see cref="IBlockTransform.Run(ILFunction, BlockTransformContext)"/>. |
|
/// </summary> |
|
public class BlockTransformContext : ILTransformContext |
|
{ |
|
/// <summary> |
|
/// The function containing the block currently being processed. |
|
/// </summary> |
|
public ILFunction Function { get; set; } |
|
|
|
/// <summary> |
|
/// The container containing the block currently being processed. |
|
/// </summary> |
|
public BlockContainer Container { get; set; } |
|
|
|
/// <summary> |
|
/// The block to process. |
|
/// </summary> |
|
/// <remarks> |
|
/// Should be identical to the <c>block</c> parameter to <c>IBlockTransform.Run</c>. |
|
/// </remarks> |
|
public Block Block { get; set; } |
|
|
|
/// <summary> |
|
/// The control flow node corresponding to the block being processed. |
|
/// </summary> |
|
public ControlFlowNode ControlFlowNode { get; set; } |
|
|
|
internal readonly Dictionary<Block, ControlFlowNode> cfg = new Dictionary<Block, ControlFlowNode>(); |
|
|
|
public BlockTransformContext(ILTransformContext context) : base(context) |
|
{ |
|
} |
|
|
|
/// <summary> |
|
/// Gets the ControlFlowNode for the block. |
|
/// Precondition: the block belonged to the <c>Container</c> at the start of the block transforms |
|
/// (when the control flow graph was created). |
|
/// </summary> |
|
public ControlFlowNode GetNode(Block block) |
|
{ |
|
return cfg[block]; |
|
} |
|
} |
|
|
|
|
|
/// <summary> |
|
/// IL transform that runs a list of per-block transforms. |
|
/// </summary> |
|
public class BlockILTransform : IILTransform |
|
{ |
|
public IList<IBlockTransform> PreOrderTransforms { get; } = new List<IBlockTransform>(); |
|
public IList<IBlockTransform> PostOrderTransforms { get; } = new List<IBlockTransform>(); |
|
|
|
public void Run(ILFunction function, ILTransformContext context) |
|
{ |
|
var blockContext = new BlockTransformContext(context); |
|
blockContext.Function = function; |
|
foreach (var container in function.Descendants.OfType<BlockContainer>()) { |
|
context.CancellationToken.ThrowIfCancellationRequested(); |
|
var cfg = LoopDetection.BuildCFG(container); |
|
Dominance.ComputeDominance(cfg[0], context.CancellationToken); |
|
|
|
blockContext.Container = container; |
|
blockContext.cfg.Clear(); |
|
for (int i = 0; i < cfg.Length; i++) { |
|
blockContext.cfg.Add(container.Blocks[i], cfg[i]); |
|
} |
|
VisitBlock(cfg[0], blockContext); |
|
// TODO: handle unreachable code? |
|
} |
|
} |
|
|
|
void VisitBlock(ControlFlowNode cfgNode, BlockTransformContext context) |
|
{ |
|
Block block = (Block)cfgNode.UserData; |
|
context.Stepper.StartGroup(block.Label, block); |
|
|
|
context.ControlFlowNode = cfgNode; |
|
context.Block = block; |
|
block.RunTransforms(PreOrderTransforms, context); |
|
|
|
// First, process the children in the dominator tree. |
|
// The ConditionDetection transform requires dominated blocks to |
|
// be already processed. |
|
foreach (var child in cfgNode.DominatorTreeChildren) { |
|
VisitBlock(child, context); |
|
} |
|
|
|
context.ControlFlowNode = cfgNode; |
|
context.Block = block; |
|
block.RunTransforms(PostOrderTransforms, context); |
|
context.Stepper.EndGroup(); |
|
} |
|
} |
|
}
|
|
|