Browse Source

Fix #2101: reset removeExtraLoad flag if keepAssignmentBefore is set; implement simple case-de-duplication: abort if there are any duplicate cases.

pull/2113/head
Siegfried Pammer 6 years ago
parent
commit
b27f08621f
  1. 41
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

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

@ -186,16 +186,29 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
} }
List<(string, ILInstruction)> values = new List<(string, ILInstruction)>(); var values = new List<(string, ILInstruction)>();
var uniqueValues = new HashSet<string>();
bool AddSwitchSection(string value, ILInstruction inst)
{
if (!uniqueValues.Add(value))
return false;
values.Add((value, inst));
return true;
}
ILInstruction switchValue = null; ILInstruction switchValue = null;
if (isVBCompareString && string.IsNullOrEmpty(firstBlockValue)) { if (isVBCompareString && string.IsNullOrEmpty(firstBlockValue)) {
values.Add((null, firstBlock ?? firstBlockOrDefaultJump)); if (!AddSwitchSection(null, firstBlock ?? firstBlockOrDefaultJump))
values.Add((string.Empty, firstBlock ?? firstBlockOrDefaultJump)); return false;
if (!AddSwitchSection(string.Empty, firstBlock ?? firstBlockOrDefaultJump))
return false;
} else { } else {
values.Add((firstBlockValue, firstBlock ?? firstBlockOrDefaultJump)); if (!AddSwitchSection(firstBlockValue, firstBlock ?? firstBlockOrDefaultJump))
return false;
} }
bool extraLoad = false; bool removeExtraLoad = false;
bool keepAssignmentBefore = false; bool keepAssignmentBefore = false;
if (i >= 1 && instructions[i - 1].MatchStLoc(switchValueVar, out switchValue)) { if (i >= 1 && instructions[i - 1].MatchStLoc(switchValueVar, out switchValue)) {
// stloc switchValueVar(switchValue) // stloc switchValueVar(switchValue)
@ -205,7 +218,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (i >= 2 && switchValue.MatchLdLoc(out var otherSwitchValueVar) && otherSwitchValueVar.IsSingleDefinition && otherSwitchValueVar.LoadCount == 1 if (i >= 2 && switchValue.MatchLdLoc(out var otherSwitchValueVar) && otherSwitchValueVar.IsSingleDefinition && otherSwitchValueVar.LoadCount == 1
&& instructions[i - 2].MatchStLoc(otherSwitchValueVar, out var newSwitchValue)) { && instructions[i - 2].MatchStLoc(otherSwitchValueVar, out var newSwitchValue)) {
switchValue = newSwitchValue; switchValue = newSwitchValue;
extraLoad = true; removeExtraLoad = true;
} }
} else if (i >= 1 && instructions[i - 1] is StLoc stloc) { } else if (i >= 1 && instructions[i - 1] is StLoc stloc) {
if (stloc.Value.MatchLdLoc(switchValueVar)) { if (stloc.Value.MatchLdLoc(switchValueVar)) {
@ -217,7 +230,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
switchValueVar = stloc.Variable; switchValueVar = stloc.Variable;
if (i >= 2 && instructions[i - 2].MatchStLoc(otherSwitchValueVar, out switchValue) if (i >= 2 && instructions[i - 2].MatchStLoc(otherSwitchValueVar, out switchValue)
&& otherSwitchValueVar.IsSingleDefinition && otherSwitchValueVar.LoadCount == 2) { && otherSwitchValueVar.IsSingleDefinition && otherSwitchValueVar.LoadCount == 2) {
extraLoad = true; removeExtraLoad = true;
} else { } else {
switchValue = new LdLoc(otherSwitchValueVar); switchValue = new LdLoc(otherSwitchValueVar);
} }
@ -238,21 +251,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILInstruction nextCaseBlock; ILInstruction nextCaseBlock;
while ((nextCaseBlock = MatchCaseBlock(currentCaseBlock, switchValueVar, out string value, out bool emptyStringEqualsNull, out Block block)) != null) { while ((nextCaseBlock = MatchCaseBlock(currentCaseBlock, switchValueVar, out string value, out bool emptyStringEqualsNull, out Block block)) != null) {
if (emptyStringEqualsNull && string.IsNullOrEmpty(value)) { if (emptyStringEqualsNull && string.IsNullOrEmpty(value)) {
values.Add((null, block)); if (!AddSwitchSection(null, block))
values.Add((string.Empty, block)); return false;
if (!AddSwitchSection(string.Empty, block))
return false;
} else { } else {
values.Add((value, block)); if (!AddSwitchSection(value, block))
return false;
} }
currentCaseBlock = nextCaseBlock as Block; currentCaseBlock = nextCaseBlock as Block;
if (currentCaseBlock == null) if (currentCaseBlock == null)
break; break;
} }
// We didn't find enough cases, exit // We didn't find enough cases, exit
if (values.Count < 3) if (values.Count < 3)
return false; return false;
// if the switchValueVar is used in other places as well, do not eliminate the store. // if the switchValueVar is used in other places as well, do not eliminate the store.
if (switchValueVar.LoadCount > values.Count) { if (switchValueVar.LoadCount > values.Count) {
keepAssignmentBefore = true; keepAssignmentBefore = true;
removeExtraLoad = false; // prevent loads from being deleted after detecting that
// we have to keep the assignment before the switch statement
switchValue = new LdLoc(switchValueVar); switchValue = new LdLoc(switchValueVar);
} }
int offset = firstBlock == null ? 1 : 0; int offset = firstBlock == null ? 1 : 0;
@ -261,7 +280,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var stringToInt = new StringToInt(switchValue, values.Skip(offset).Select(item => item.Item1).ToArray()); var stringToInt = new StringToInt(switchValue, values.Skip(offset).Select(item => item.Item1).ToArray());
var inst = new SwitchInstruction(stringToInt); var inst = new SwitchInstruction(stringToInt);
inst.Sections.AddRange(sections); inst.Sections.AddRange(sections);
if (extraLoad) { if (removeExtraLoad) {
inst.AddILRange(instructions[i - 2]); inst.AddILRange(instructions[i - 2]);
instructions[i - 2].ReplaceWith(inst); instructions[i - 2].ReplaceWith(inst);
instructions.RemoveRange(i - 1, 3); instructions.RemoveRange(i - 1, 3);

Loading…
Cancel
Save