This commit is contained in:
jfrijters 2010-10-08 08:06:54 +00:00
Родитель f30b42d0ca
Коммит b4d6193115
1 изменённых файлов: 294 добавлений и 12 удалений

Просмотреть файл

@ -151,6 +151,13 @@ namespace IKVM.Internal
this.data = data;
}
internal bool Match(OpCodeWrapper other)
{
return other.pseudo == pseudo
&& other.opcode == opcode
&& (other.data == data || (data != null && data.Equals(other.data)));
}
internal bool HasLabel
{
get { return data is CodeEmitterLabel; }
@ -361,6 +368,11 @@ namespace IKVM.Internal
codeEmitter.RealEmitPseudoOpCode(ilOffset, pseudo, data);
}
}
public override string ToString()
{
return pseudo.ToString() + " " + data;
}
}
sealed class CalliWrapper
@ -549,13 +561,23 @@ namespace IKVM.Internal
{
for (int i = 1; i < code.Count; i++)
{
if (code[i].pseudo == CodeType.Label
&& code[i - 1].opcode == OpCodes.Br
if (code[i].pseudo == CodeType.Label)
{
if (code[i - 1].opcode == OpCodes.Br
&& code[i - 1].MatchLabel(code[i]))
{
code.RemoveAt(i - 1);
i--;
}
else if (i >= 2
&& code[i - 1].pseudo == CodeType.LineNumber
&& code[i - 2].opcode == OpCodes.Br
&& code[i - 2].MatchLabel(code[i]))
{
code.RemoveAt(i - 2);
i--;
}
}
}
}
@ -1053,7 +1075,7 @@ namespace IKVM.Internal
}
}
private void BubblePopsAndReleaseTempLocals()
private void SortPseudoOpCodes()
{
for (int i = 0; i < code.Count - 1; i++)
{
@ -1066,7 +1088,7 @@ namespace IKVM.Internal
OpCodeWrapper temp = code[i];
code[i] = code[i + 1];
code[i + 1] = temp;
i -= 2;
i--;
}
break;
case CodeType.BeginExceptionBlock:
@ -1075,7 +1097,16 @@ namespace IKVM.Internal
OpCodeWrapper temp = code[i];
code[i] = code[i + 1];
code[i + 1] = temp;
i -= 2;
i--;
}
break;
case CodeType.Label:
if (code[i + 1].pseudo == CodeType.BeginExceptionBlock)
{
OpCodeWrapper temp = code[i];
code[i] = code[i + 1];
code[i + 1] = temp;
i--;
}
break;
}
@ -1273,6 +1304,253 @@ namespace IKVM.Internal
}
}
}
// 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: ;
}
}
private void DeduplicateBranchSourceTargetCode()
{
for (int i = 0; i < code.Count; i++)
{
if (code[i].pseudo == CodeType.Label)
{
code[i].Label.Temp = i;
}
}
for (int i = 0; i < code.Count; i++)
{
if (code[i].opcode == OpCodes.Br && code[i].HasLabel)
{
int source = i - 1;
int target = code[i].Label.Temp - 1;
while (source >= 0 && target >= 0)
{
switch (code[source].pseudo)
{
case CodeType.LineNumber:
case CodeType.OpCode:
break;
default:
goto break_while;
}
if (!code[source].Match(code[target]))
{
break;
}
switch (code[source].opcode.FlowControl)
{
case FlowControl.Branch:
case FlowControl.Cond_Branch:
goto break_while;
}
source--;
target--;
}
break_while: ;
source++;
target++;
if (source != i && target > 0 && source != target - 1)
{
// TODO for now we only do this optimization if there happens to be an appriopriate label
if (code[target - 1].pseudo == CodeType.Label)
{
code[source] = new OpCodeWrapper(OpCodes.Br, code[target - 1].Label);
for (int j = source + 1; j < i; j++)
{
// This is to make sure that any line numbers here are removed by DCE.
// It may be better to fix DCE to remove unreachable line numbers.
code[j] = new OpCodeWrapper(OpCodes.Nop, null);
}
}
}
}
}
}
private void OptimizeStackTransfer()
{
for (int i = 0; i < code.Count; i++)
{
if (code[i].opcode == OpCodes.Ldloc
&& code[i + 1].opcode == OpCodes.Stloc
&& code[i + 2].pseudo == CodeType.BeginExceptionBlock
&& code[i + 3].opcode == OpCodes.Ldloc && code[i + 3].MatchLocal(code[i + 1])
&& code[i + 4].pseudo == CodeType.ReleaseTempLocal && code[i + 4].MatchLocal(code[i + 3]))
{
code[i + 1] = code[i];
code[i] = code[i + 2];
code.RemoveRange(i + 2, 3);
}
}
}
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: ;
}
}
}
private bool HasBranchTo(int start, int end, CodeEmitterLabel label)
{
for (int i = start; i < end; i++)
{
if (code[i].HasLabel)
{
if (code[i].Label == label)
{
return true;
}
}
else if (code[i].opcode == OpCodes.Switch)
{
foreach (CodeEmitterLabel swlbl in code[i].Labels)
{
if (swlbl == label)
{
return true;
}
}
}
}
return false;
}
private bool MatchHandlers(int beginFault1, int beginFault2, int length)
{
for (int i = 0; i < length; i++)
{
if (!code[beginFault1 + i].Match(code[beginFault2 + i]))
{
return false;
}
}
return true;
}
private bool IsFaultOnlyBlock(int[] extra, int begin)
{
return code[extra[begin]].pseudo == CodeType.BeginFaultBlock
&& code[extra[extra[begin]]].pseudo == CodeType.EndExceptionBlock;
}
internal void DoEmit()
@ -1280,16 +1558,20 @@ namespace IKVM.Internal
OptimizePatterns();
#if STATIC_COMPILER
for (int i = 0; i < 2; i++)
for (int i = 0; i < 4; i++)
{
RemoveJumpNext();
ChaseBranches();
RemoveUnusedLabels();
BubblePopsAndReleaseTempLocals();
SortPseudoOpCodes();
AnnihilatePops();
AnnihilateStoreReleaseTempLocals();
DeduplicateBranchSourceTargetCode();
OptimizeStackTransfer();
MergeExceptionBlocks();
RemoveDeadCode();
}
//DumpMethod();
OptimizeEncodings();
OptimizeBranchSizes();
@ -1315,11 +1597,11 @@ namespace IKVM.Internal
{
if (code[i].pseudo == CodeType.OpCode)
{
Console.WriteLine(code[i].opcode.Name);
Console.WriteLine(" " + code[i].opcode.Name);
}
else
{
Console.WriteLine(code[i].pseudo);
Console.WriteLine(code[i]);
}
}
}