private void MergeExceptionBlocks()
{
// The first loop will convert all Begin[Exception|Catch|Fault|Finally]Block and EndExceptionBlock
// pseudo opcodes into a cyclic linked list (EndExceptionBlock links back to BeginExceptionBlock)
// to allow for easy traversal in the next loop.
int[] extra = new int[code.Count];
Stack<int> stack = new Stack<int>();
int currentBeginExceptionBlock = -1;
int currentLast = -1;
for (int i = 0; i < code.Count; i++)
{
switch (code[i].pseudo)
{
case CodeType.BeginExceptionBlock:
stack.Push(currentBeginExceptionBlock);
currentBeginExceptionBlock = i;
currentLast = i;
break;
case CodeType.EndExceptionBlock:
extra[currentLast] = i;
extra[i] = currentBeginExceptionBlock;
currentBeginExceptionBlock = stack.Pop();
currentLast = currentBeginExceptionBlock;
if (currentLast != -1)
{
while (extra[currentLast] != 0)
{
currentLast = extra[currentLast];
}
}
break;
case CodeType.BeginCatchBlock:
case CodeType.BeginFaultBlock:
case CodeType.BeginFinallyBlock:
extra[currentLast] = i;
currentLast = i;
break;
}
}
// Now we look for consecutive exception blocks that have the same fault handler
for (int i = 0; i < code.Count - 1; i++)
{
if (code[i].pseudo == CodeType.EndExceptionBlock
&& code[i + 1].pseudo == CodeType.BeginExceptionBlock)
{
if (IsFaultOnlyBlock(extra, extra[i]) && IsFaultOnlyBlock(extra, i + 1))
{
int beginFault1 = extra[extra[i]];
int beginFault2 = extra[i + 1];
int length1 = extra[beginFault1] - beginFault1;
int length2 = extra[beginFault2] - beginFault2;
if (length1 == length2 && MatchHandlers(beginFault1, beginFault2, length1))
{
// Check if the labels at the start of the handler are reachable from outside
// of the new combined block.
for (int j = i + 2; j < beginFault2; j++)
{
if (code[j].pseudo == CodeType.OpCode)
{
break;
}
else if (code[j].pseudo == CodeType.Label)
{
if (HasBranchTo(0, extra[i], code[j].Label)
|| HasBranchTo(beginFault2 + length2, code.Count, code[j].Label))
{
goto no_merge;
}
}
}
// Merge the two blocks by overwritting the first fault block and
// the BeginExceptionBlock of the second block.
for (int j = beginFault1; j < i + 2; j++)
{
code[j] = new OpCodeWrapper(OpCodes.Nop, null);
}
// Repair the linking structure.
extra[extra[i]] = beginFault2;
extra[extra[beginFault2]] = extra[i];
}
}
no_merge: ;
}
}
}