using System.Collections.Generic; using System.Linq; using ICSharpCode.Decompiler.FlowAnalysis; using ICSharpCode.Decompiler.IL.ControlFlow; namespace ICSharpCode.Decompiler.IL.Transforms { /// /// Per-block IL transform. /// public interface IBlockTransform { void Run(Block block, BlockTransformContext context); } /// /// Parameter class holding various arguments for . /// public class BlockTransformContext : ILTransformContext { /// /// The function containing the block currently being processed. /// public ILFunction Function { get; set; } /// /// The container containing the block currently being processed. /// public BlockContainer Container { get; set; } /// /// The block to process. /// /// /// Should be identical to the block parameter to IBlockTransform.Run. /// public Block Block { get; set; } /// /// The control flow node corresponding to the block being processed. /// public ControlFlowNode ControlFlowNode { get; set; } internal readonly Dictionary cfg = new Dictionary(); public BlockTransformContext(ILTransformContext context) : base(context) { } /// /// Gets the ControlFlowNode for the block. /// Precondition: the block belonged to the Container at the start of the block transforms /// (when the control flow graph was created). /// public ControlFlowNode GetNode(Block block) { return cfg[block]; } } /// /// IL transform that runs a list of per-block transforms. /// public class BlockILTransform : IILTransform { public IList PreOrderTransforms { get; } = new List(); public IList PostOrderTransforms { get; } = new List(); public void Run(ILFunction function, ILTransformContext context) { var blockContext = new BlockTransformContext(context); blockContext.Function = function; foreach (var container in function.Descendants.OfType().ToList()) { 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(); } } }