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.
		
		
		
		
		
			
		
			
				
					
					
						
							117 lines
						
					
					
						
							3.7 KiB
						
					
					
				
			
		
		
	
	
							117 lines
						
					
					
						
							3.7 KiB
						
					
					
				using System; | 
						|
using System.Collections.Generic; | 
						|
using System.Diagnostics; | 
						|
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 | 
						|
	{ | 
						|
		/// <summary> | 
						|
		/// Runs the transform on the specified block. | 
						|
		///  | 
						|
		/// Note: the transform may only modify the specified block and its descendants, | 
						|
		/// as well as any sibling blocks that are dominated by the specified block. | 
						|
		/// </summary> | 
						|
		void Run(Block block, BlockTransformContext context); | 
						|
	} | 
						|
 | 
						|
	/// <summary> | 
						|
	/// Parameter class holding various arguments for <see cref="IBlockTransform.Run"/>. | 
						|
	/// </summary> | 
						|
	public class BlockTransformContext : ILTransformContext | 
						|
	{ | 
						|
		/// <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> | 
						|
		/// <remarks> | 
						|
		/// Identical to <c>ControlFlowGraph.GetNode(Block)</c>. | 
						|
		/// Note: the control flow graph is not up-to-date, but was created at the start of the | 
						|
		/// block transforms (before loop detection). | 
						|
		/// </remarks> | 
						|
		public ControlFlowNode ControlFlowNode { get; set; } | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets the control flow graph. | 
						|
		///  | 
						|
		/// Note: the control flow graph is not up-to-date, but was created at the start of the | 
						|
		/// block transforms (before loop detection). | 
						|
		/// </summary> | 
						|
		public ControlFlowGraph ControlFlowGraph { get; set; } | 
						|
 | 
						|
		public BlockTransformContext(ILTransformContext context) : base(context) | 
						|
		{ | 
						|
		} | 
						|
	} | 
						|
 | 
						|
 | 
						|
	/// <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>(); | 
						|
 | 
						|
		bool running; | 
						|
 | 
						|
		public override string ToString() | 
						|
		{ | 
						|
			return $"{nameof(BlockILTransform)} ({string.Join(", ", PreOrderTransforms.Concat(PostOrderTransforms).Select(t => t.GetType().Name))})"; | 
						|
		} | 
						|
 | 
						|
		public void Run(ILFunction function, ILTransformContext context) | 
						|
		{ | 
						|
			if (running) | 
						|
				throw new InvalidOperationException("Reentrancy detected. Transforms (and the CSharpDecompiler) are neither neither thread-safe nor re-entrant."); | 
						|
			try { | 
						|
				running = true; | 
						|
				var blockContext = new BlockTransformContext(context); | 
						|
				Debug.Assert(blockContext.Function == function); | 
						|
				foreach (var container in function.Descendants.OfType<BlockContainer>().ToList()) { | 
						|
					context.CancellationToken.ThrowIfCancellationRequested(); | 
						|
					blockContext.ControlFlowGraph = new ControlFlowGraph(container, context.CancellationToken); | 
						|
					VisitBlock(blockContext.ControlFlowGraph.GetNode(container.EntryPoint), blockContext); | 
						|
					// TODO: handle unreachable code? | 
						|
				} | 
						|
			} finally { | 
						|
				running = false; | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		void VisitBlock(ControlFlowNode cfgNode, BlockTransformContext context) | 
						|
		{ | 
						|
			Block block = (Block)cfgNode.UserData; | 
						|
			context.StepStartGroup(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.StepEndGroup(); | 
						|
		} | 
						|
	} | 
						|
}
 | 
						|
 |