private void RemoveDeadCode()
{
for (int i = 0; i < code.Count; i++)
{
if (code[i].pseudo == CodeType.Label)
{
code[i].Label.Temp = 0;
}
}
const int ReachableFlag = 1;
const int ProcessedFlag = 2;
bool reachable = true;
bool done = false;
while (!done)
{
done = true;
for (int i = 0; i < code.Count; i++)
{
if (reachable)
{
if (code[i].pseudo == CodeType.Label)
{
if (code[i].Label.Temp == ProcessedFlag)
{
done = false;
}
code[i].Label.Temp |= ReachableFlag;
}
else if (code[i].pseudo == CodeType.OpCode)
{
if (code[i].HasLabel)
{
if (code[i].Label.Temp == ProcessedFlag)
{
done = false;
}
code[i].Label.Temp |= ReachableFlag;
}
else if (code[i].opcode == OpCodes.Switch)
{
foreach (CodeEmitterLabel label in code[i].Labels)
{
if (label.Temp == ProcessedFlag)
{
done = false;
}
label.Temp |= ReachableFlag;
}
}
switch (code[i].opcode.FlowControl)
{
case FlowControl.Cond_Branch:
if (!code[i].HasLabel && code[i].opcode != OpCodes.Switch)
{
throw new NotSupportedException();
}
break;
case FlowControl.Branch:
if (code[i].HasLabel)
{
reachable = false;
}
else if (code[i].HasValueByte && code[i].ValueByte == 0)
{
// it's a "leave_s 0", so the next instruction is reachable
}
else
{
throw new NotSupportedException();
}
break;
case FlowControl.Return:
case FlowControl.Throw:
reachable = false;
break;
}
}
}
else if (code[i].pseudo == CodeType.BeginCatchBlock)
{
reachable = true;
}
else if (code[i].pseudo == CodeType.BeginFaultBlock)
{
reachable = true;
}
else if (code[i].pseudo == CodeType.BeginFinallyBlock)
{
reachable = true;
}
else if (code[i].pseudo == CodeType.Label && (code[i].Label.Temp & ReachableFlag) != 0)
{
reachable = true;
}
if (code[i].pseudo == CodeType.Label)
{
code[i].Label.Temp |= ProcessedFlag;
}
}
}
reachable = true;
int firstUnreachable = -1;
for (int i = 0; i < code.Count; i++)
{
if (reachable)
{
if (code[i].pseudo == CodeType.OpCode)
{
switch (code[i].opcode.FlowControl)
{
case FlowControl.Branch:
if (code[i].HasValueByte && code[i].ValueByte == 0)
{
// it's a "leave_s 0", so the next instruction is reachable
}
else
{
goto case FlowControl.Return;
}
break;
case FlowControl.Return:
case FlowControl.Throw:
reachable = false;
firstUnreachable = i + 1;
break;
}
}
}
else
{
switch (code[i].pseudo)
{
case CodeType.OpCode:
break;
case CodeType.Label:
if ((code[i].Label.Temp & ReachableFlag) != 0)
{
goto case CodeType.BeginCatchBlock;
}
break;
case CodeType.BeginCatchBlock:
case CodeType.BeginFaultBlock:
case CodeType.BeginFinallyBlock:
code.RemoveRange(firstUnreachable, i - firstUnreachable);
i = firstUnreachable;
firstUnreachable = -1;
reachable = true;
break;
default:
code.RemoveRange(firstUnreachable, i - firstUnreachable);
i = firstUnreachable;
firstUnreachable++;
break;
}
}
}
if (!reachable)
{
code.RemoveRange(firstUnreachable, code.Count - firstUnreachable);
}
// TODO can't we incorporate this in the above code?
// remove exception blocks with empty try blocks
// (which can happen if the try block is unreachable)
for (int i = 0; i < code.Count; i++)
{
restart:
if (code[i].pseudo == CodeType.BeginExceptionBlock)
{
for (int k = 0; ; k++)
{
switch (code[i + k].pseudo)
{
case CodeType.BeginCatchBlock:
case CodeType.BeginFaultBlock:
case CodeType.BeginFinallyBlock:
int depth = 0;
for (int j = i + 1; ; j++)
{
switch (code[j].pseudo)
{
case CodeType.BeginExceptionBlock:
depth++;
break;
case CodeType.EndExceptionBlock:
if (depth == 0)
{
code.RemoveRange(i, (j - i) + 1);
goto restart;
}
depth--;
break;
}
}
case CodeType.OpCode:
goto next;
}
}
}
next: ;
}
}