Browse Source

SwitchOnStringTransform: Remove extra variables introduced by switch pattern.

pull/887/head
Siegfried Pammer 9 years ago
parent
commit
67272e58ef
  1. 2
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
  2. 46
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

2
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs

@ -413,7 +413,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public static void SwitchWithComplexCondition(string[] args) public static void SwitchWithComplexCondition(string[] args)
{ {
switch (args.Length == 0 ? "dummy" : args[0]) { switch ((args.Length == 0) ? "dummy" : args[0]) {
case "a": { case "a": {
Console.WriteLine("a"); Console.WriteLine("a");
break; break;

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

@ -65,17 +65,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms
changed = true; changed = true;
continue; continue;
} }
if (MatchLegacySwitchOnStringWithDict(block.Instructions, i, out newSwitch)) { if (MatchLegacySwitchOnStringWithDict(block.Instructions, i, out newSwitch, out keepAssignmentBefore)) {
block.Instructions[i + 1].ReplaceWith(newSwitch); block.Instructions[i + 1].ReplaceWith(newSwitch);
block.Instructions.RemoveAt(i); if (keepAssignmentBefore) {
block.Instructions.RemoveAt(i);
i--;
} else {
block.Instructions.RemoveRange(i - 1, 2);
i -= 2;
}
changed = true; changed = true;
continue; continue;
} }
if (MatchRoslynSwitchOnString(block.Instructions, i, out newSwitch)) { if (MatchRoslynSwitchOnString(block.Instructions, i, out newSwitch, out keepAssignmentBefore)) {
block.Instructions[i - 1].ReplaceWith(newSwitch); block.Instructions[i].ReplaceWith(newSwitch);
block.Instructions.RemoveAt(i); if (keepAssignmentBefore) {
block.Instructions.RemoveAt(i - 1);
i--;
} else {
block.Instructions.RemoveRange(i - 2, 2);
i -= 2;
}
changed = true; changed = true;
i--;
continue; continue;
} }
} }
@ -217,14 +228,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// <summary> /// <summary>
/// Matches the C# 2.0 switch-on-string pattern, which uses Dictionary&lt;string, int&gt;. /// Matches the C# 2.0 switch-on-string pattern, which uses Dictionary&lt;string, int&gt;.
/// </summary> /// </summary>
bool MatchLegacySwitchOnStringWithDict(InstructionCollection<ILInstruction> instructions, int i, out SwitchInstruction inst) bool MatchLegacySwitchOnStringWithDict(InstructionCollection<ILInstruction> instructions, int i, out SwitchInstruction inst, out bool keepAssignmentBefore)
{ {
inst = null; inst = null;
keepAssignmentBefore = false;
if (i < 1) return false; if (i < 1) return false;
// match first block: checking switch-value for null // match first block: checking switch-value for null
if (!(instructions[i].MatchIfInstruction(out var condition, out var exitBlockJump) && if (!(instructions[i].MatchIfInstruction(out var condition, out var exitBlockJump) &&
instructions[i - 1].MatchStLoc(out var switchValueVar, out var switchValue) && switchValueVar.Type.IsKnownType(KnownTypeCode.String))) instructions[i - 1].MatchStLoc(out var switchValueVar, out var switchValue) && switchValueVar.Type.IsKnownType(KnownTypeCode.String)))
return false; return false;
if (!switchValueVar.IsSingleDefinition)
return false;
if (!exitBlockJump.MatchBranch(out var nullValueCaseBlock)) if (!exitBlockJump.MatchBranch(out var nullValueCaseBlock))
return false; return false;
if (!(condition.MatchCompEquals(out var left, out var right) && right.MatchLdNull() && (left.Match(switchValue).Success || left.MatchLdLoc(switchValueVar)))) if (!(condition.MatchCompEquals(out var left, out var right) && right.MatchLdNull() && (left.Match(switchValue).Success || left.MatchLdLoc(switchValueVar))))
@ -279,7 +293,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
stringValues.Add(null); stringValues.Add(null);
sections.Add(new SwitchSection() { Labels = label, Body = new Branch(nullValueCaseBlock) }); sections.Add(new SwitchSection() { Labels = label, Body = new Branch(nullValueCaseBlock) });
} }
var stringToInt = new StringToInt(new LdLoc(switchValueVar), stringValues.ToArray()); if (switchValueVar.LoadCount > 2) {
switchValue = new LdLoc(switchValueVar);
keepAssignmentBefore = true;
}
var stringToInt = new StringToInt(switchValue, stringValues.ToArray());
inst = new SwitchInstruction(stringToInt); inst = new SwitchInstruction(stringToInt);
inst.Sections.AddRange(sections); inst.Sections.AddRange(sections);
return true; return true;
@ -434,9 +452,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true; return true;
} }
bool MatchRoslynSwitchOnString(InstructionCollection<ILInstruction> instructions, int i, out SwitchInstruction inst) bool MatchRoslynSwitchOnString(InstructionCollection<ILInstruction> instructions, int i, out SwitchInstruction inst, out bool keepAssignmentBefore)
{ {
inst = null; inst = null;
keepAssignmentBefore = false;
if (i < 1) return false; if (i < 1) return false;
if (!(instructions[i] is SwitchInstruction switchInst && switchInst.Value.MatchLdLoc(out var targetVar) && if (!(instructions[i] is SwitchInstruction switchInst && switchInst.Value.MatchLdLoc(out var targetVar) &&
MatchComputeStringHashCall(instructions[i - 1], targetVar, out var switchValue))) MatchComputeStringHashCall(instructions[i - 1], targetVar, out var switchValue)))
@ -473,8 +492,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
stringValues.Add((index++, stringValue, body)); stringValues.Add((index++, stringValue, body));
} }
ILInstruction switchValueInst = switchValue;
if (i > 1 && instructions[i - 2].MatchStLoc(switchValue.Variable, out var switchValueTmp) &&
switchValue.Variable.IsSingleDefinition && switchValue.Variable.LoadCount == switchInst.Sections.Count) {
switchValueInst = switchValueTmp;
} else {
keepAssignmentBefore = true;
}
var defaultLabel = new LongSet(new LongInterval(0, index)).Invert(); var defaultLabel = new LongSet(new LongInterval(0, index)).Invert();
var value = new StringToInt(switchValue.Clone(), stringValues.Select(item => item.Item2).ToArray()); var value = new StringToInt(switchValueInst, stringValues.Select(item => item.Item2).ToArray());
inst = new SwitchInstruction(value); inst = new SwitchInstruction(value);
inst.Sections.AddRange(stringValues.Select(section => new SwitchSection { Labels = new Util.LongSet(section.Item1), Body = new Branch(section.Item3) })); inst.Sections.AddRange(stringValues.Select(section => new SwitchSection { Labels = new Util.LongSet(section.Item1), Body = new Branch(section.Item3) }));
inst.Sections.Add(new SwitchSection { Labels = defaultLabel, Body = defaultBranch }); inst.Sections.Add(new SwitchSection { Labels = defaultLabel, Body = defaultBranch });

Loading…
Cancel
Save