From 0b5d4d864ccccf87856354922fdda658aeb8db15 Mon Sep 17 00:00:00 2001 From: de4dot Date: Thu, 15 Dec 2011 10:04:04 +0100 Subject: [PATCH] Remove nop blocks --- blocks/Block.cs | 22 +++++++++++++++++++ blocks/Blocks.cs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/blocks/Block.cs b/blocks/Block.cs index 92a9a19b..4d1fbfc3 100644 --- a/blocks/Block.cs +++ b/blocks/Block.cs @@ -143,6 +143,18 @@ namespace de4dot.blocks { replaceLastInstrsWithBranch(1, target); } + public void setNewFallThrough(Block newFallThrough) { + disconnectFromFallThrough(); + fallThrough = newFallThrough; + newFallThrough.sources.Add(this); + } + + public void setNewTarget(int index, Block newTarget) { + disconnectFromBlock(targets[index]); + targets[index] = newTarget; + newTarget.sources.Add(this); + } + public void removeDeadBlock() { if (sources.Count != 0) throw new ApplicationException("Trying to remove a non-dead block"); @@ -284,5 +296,15 @@ namespace de4dot.blocks { public bool isConditionalBranch() { return LastInstr.isConditionalBranch(); } + + public bool isNopBlock() { + if (!isFallThrough()) + return false; + foreach (var instr in instructions) { + if (instr.OpCode.Code != Code.Nop) + return false; + } + return true; + } } } diff --git a/blocks/Blocks.cs b/blocks/Blocks.cs index a888e9f7..9e00a6f2 100644 --- a/blocks/Blocks.cs +++ b/blocks/Blocks.cs @@ -183,6 +183,7 @@ namespace de4dot.blocks { } public void repartitionBlocks() { + mergeNopBlocks(); foreach (var scopeBlock in getAllScopeBlocks(methodBlocks)) { try { scopeBlock.repartitionBlocks(); @@ -194,5 +195,61 @@ namespace de4dot.blocks { } } } + + void mergeNopBlocks() { + var allBlocks = methodBlocks.getAllBlocks(); + + var nopBlocks = new Dictionary(); + foreach (var nopBlock in allBlocks) { + if (nopBlock.isNopBlock()) + nopBlocks[nopBlock] = true; + } + + if (nopBlocks.Count == 0) + return; + + for (int i = 0; i < 10; i++) { + bool changed = false; + + foreach (var block in allBlocks) { + Block nopBlockTarget; + + nopBlockTarget = getNopBlockTarget(nopBlocks, block, block.FallThrough); + if (nopBlockTarget != null) { + block.setNewFallThrough(nopBlockTarget); + changed = true; + } + + if (block.Targets != null) { + for (int targetIndex = 0; targetIndex < block.Targets.Count; targetIndex++) { + nopBlockTarget = getNopBlockTarget(nopBlocks, block, block.Targets[targetIndex]); + if (nopBlockTarget == null) + continue; + block.setNewTarget(targetIndex, nopBlockTarget); + changed = true; + } + } + } + + if (!changed) + break; + } + + foreach (var nopBlock in nopBlocks.Keys) { + var scopeBlock = (ScopeBlock)nopBlock.Parent; + scopeBlock.removeDeadBlock(nopBlock); + } + } + + static Block getNopBlockTarget(Dictionary nopBlocks, Block source, Block nopBlock) { + if (nopBlock == null || !nopBlocks.ContainsKey(nopBlock) || source == nopBlock.FallThrough) + return null; + if (((ScopeBlock)nopBlock.Parent).BaseBlocks[0] == nopBlock) + return null; + var target = nopBlock.FallThrough; + if (nopBlock.Parent != target.Parent) + return null; + return target; + } } }