|
|
|
@ -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); |
|
|
|
|