Browse Source

Code cleanup SwitchOnStringTransform.

pull/887/head
Daniel Grunwald 8 years ago
parent
commit
2824906f8f
  1. 52
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

52
ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

@ -265,14 +265,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var sections = new List<SwitchSection>(switchInst.Sections); var sections = new List<SwitchSection>(switchInst.Sections);
// switch contains case null: // switch contains case null:
if (nullValueCaseBlock != defaultBlock) { if (nullValueCaseBlock != defaultBlock) {
var label = new Util.LongSet(switchInst.Sections.Count); if (!AddNullSection(sections, stringValues, nullValueCaseBlock)) {
var possibleConflicts = switchInst.Sections.Where(sec => sec.Labels.Overlaps(label)).ToArray();
if (possibleConflicts.Length > 1)
return false; return false;
else if (possibleConflicts.Length == 1) }
possibleConflicts[0].Labels = possibleConflicts[0].Labels.ExceptWith(label);
stringValues.Add(null);
sections.Add(new SwitchSection() { Labels = label, Body = new Branch(nullValueCaseBlock) });
} }
bool keepAssignmentBefore = false; bool keepAssignmentBefore = false;
if (switchValueVar.LoadCount > 2) { if (switchValueVar.LoadCount > 2) {
@ -284,15 +279,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms
inst.Sections.AddRange(sections); inst.Sections.AddRange(sections);
instructions[i + 1].ReplaceWith(inst); instructions[i + 1].ReplaceWith(inst);
if (keepAssignmentBefore) { if (keepAssignmentBefore) {
// delete if (comp(ldloc switchValueVar == ldnull))
instructions.RemoveAt(i); instructions.RemoveAt(i);
i--; i--;
} else { } else {
// delete both the if and the assignment before
instructions.RemoveRange(i - 1, 2); instructions.RemoveRange(i - 1, 2);
i -= 2; i -= 2;
} }
return true; return true;
} }
private bool AddNullSection(List<SwitchSection> sections, List<string> stringValues, Block nullValueCaseBlock)
{
var label = new LongSet(sections.Count);
var possibleConflicts = sections.Where(sec => sec.Labels.Overlaps(label)).ToArray();
if (possibleConflicts.Length > 1)
return false;
else if (possibleConflicts.Length == 1) {
if (possibleConflicts[0].Labels.Count() == 1)
return false; // cannot remove only label
possibleConflicts[0].Labels = possibleConflicts[0].Labels.ExceptWith(label);
}
stringValues.Add(null);
sections.Add(new SwitchSection() { Labels = label, Body = new Branch(nullValueCaseBlock) });
return true;
}
/// <summary> /// <summary>
/// Matches 'volatile.ldobj dictionaryType(ldsflda dictField)' /// Matches 'volatile.ldobj dictionaryType(ldsflda dictField)'
/// </summary> /// </summary>
@ -457,14 +470,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var sections = new List<SwitchSection>(switchInst.Sections); var sections = new List<SwitchSection>(switchInst.Sections);
// switch contains case null: // switch contains case null:
if (nullCaseBlock != defaultBlock) { if (nullCaseBlock != defaultBlock) {
var label = new Util.LongSet(switchInst.Sections.Count); if (!AddNullSection(sections, stringValues, nullCaseBlock)) {
var possibleConflicts = switchInst.Sections.Where(sec => sec.Labels.Overlaps(label)).ToArray();
if (possibleConflicts.Length > 1)
return false; return false;
else if (possibleConflicts.Length == 1) }
possibleConflicts[0].Labels = possibleConflicts[0].Labels.ExceptWith(label);
stringValues.Add(null);
sections.Add(new SwitchSection() { Labels = label, Body = new Branch(nullCaseBlock) });
} }
var stringToInt = new StringToInt(switchValue, stringValues.ToArray()); var stringToInt = new StringToInt(switchValue, stringValues.ToArray());
var inst = new SwitchInstruction(stringToInt); var inst = new SwitchInstruction(stringToInt);
@ -501,12 +509,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
ILInstruction switchValueInst = switchValueLoad; ILInstruction switchValueInst = switchValueLoad;
// stloc switchValueLoadVariable(switchValue) // stloc switchValueLoadVariable(switchValue)
// stloc switchValueVar(call ComputeStringHash(ldloc V_0)) // stloc switchValueVar(call ComputeStringHash(ldloc switchValueLoadVariable))
// switch (ldloc switchValueVar) { // switch (ldloc switchValueVar) {
bool keepAssignmentBefore; bool keepAssignmentBefore;
// if the switchValueLoad.Variable is only used in the compiler generated case equality checks, we can remove it. // if the switchValueLoad.Variable is only used in the compiler generated case equality checks, we can remove it.
if (i > 1 && instructions[i - 2].MatchStLoc(switchValueLoad.Variable, out var switchValueTmp) && if (i > 1 && instructions[i - 2].MatchStLoc(switchValueLoad.Variable, out var switchValueTmp) &&
switchValueLoad.Variable.IsSingleDefinition && switchValueLoad.Variable.LoadCount == switchInst.Sections.Count) { switchValueLoad.Variable.IsSingleDefinition && switchValueLoad.Variable.LoadCount == switchInst.Sections.Count)
{
switchValueInst = switchValueTmp; switchValueInst = switchValueTmp;
keepAssignmentBefore = false; keepAssignmentBefore = false;
} else { } else {
@ -542,19 +551,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!bodyBranch.MatchBranch(out body)) if (!bodyBranch.MatchBranch(out body))
return false; return false;
if (!MatchStringEqualityComparison(condition, switchValueVar, out stringValue)) { if (MatchStringEqualityComparison(condition, switchValueVar, out stringValue)) {
if (condition.MatchLogicNot(out condition) && MatchStringEqualityComparison(condition, switchValueVar, out stringValue)) { return body != null;
} else if (condition.MatchLogicNot(out condition) && MatchStringEqualityComparison(condition, switchValueVar, out stringValue)) {
if (!target.Instructions[1].MatchBranch(out Block exit)) if (!target.Instructions[1].MatchBranch(out Block exit))
return false; return false;
body = exit; body = exit;
} else return true;
} else {
return false; return false;
} }
return body != null;
} }
/// <summary> /// <summary>
/// Matches 'stloc(targetVar, call ComputeStringHash(ldloc(switchValue)))' /// Matches 'stloc(targetVar, call ComputeStringHash(ldloc switchValue))'
/// </summary> /// </summary>
bool MatchComputeStringHashCall(ILInstruction inst, ILVariable targetVar, out LdLoc switchValue) bool MatchComputeStringHashCall(ILInstruction inst, ILVariable targetVar, out LdLoc switchValue)
{ {

Loading…
Cancel
Save