Remove nop blocks

This commit is contained in:
de4dot 2011-12-15 10:04:04 +01:00
parent a3c9221410
commit 0b5d4d864c
2 changed files with 79 additions and 0 deletions

View File

@ -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;
}
}
}

View File

@ -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<Block, bool>();
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<Block, bool> 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;
}
}
}