Browse Source

Fix #3069: Reuse SwitchAnalysis instead of MatchIfElseOnCharBlock

release/8.1
Siegfried Pammer 2 years ago
parent
commit
d25980b23c
  1. 2
      ICSharpCode.Decompiler/IL/ControlFlow/SwitchAnalysis.cs
  2. 77
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

2
ICSharpCode.Decompiler/IL/ControlFlow/SwitchAnalysis.cs

@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
public ILVariable SwitchVariable => switchVar; public ILVariable SwitchVariable => switchVar;
/// <summary> /// <summary>
/// Whether at least one the analyzed blocks contained an IL switch constructors. /// Whether at least one of the analyzed blocks contained an IL switch constructors.
/// </summary> /// </summary>
public bool ContainsILSwitch { get; private set; } public bool ContainsILSwitch { get; private set; }

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

@ -34,6 +34,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public class SwitchOnStringTransform : IILTransform public class SwitchOnStringTransform : IILTransform
{ {
ILTransformContext context; ILTransformContext context;
private readonly SwitchAnalysis analysis = new SwitchAnalysis();
public void Run(ILFunction function, ILTransformContext context) public void Run(ILFunction function, ILTransformContext context)
{ {
@ -1191,8 +1192,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
else else
{ {
int length = (int)block.Length.Intervals[0].Start; int length = (int)block.Length.Intervals[0].Start;
if (MatchSwitchOnCharBlock(block.TargetBlock, length, switchValueVar, out var mapping) if (MatchSwitchOnCharBlock(block.TargetBlock, length, switchValueVar, out var mapping))
|| MatchIfElseOnCharBlock(block.TargetBlock, length, switchValueVar, out mapping))
{ {
foreach (var item in mapping) foreach (var item in mapping)
{ {
@ -1277,6 +1277,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (block.IncomingEdgeCount != 1) if (block.IncomingEdgeCount != 1)
return false; return false;
SwitchInstruction @switch; SwitchInstruction @switch;
List<KeyValuePair<LongSet, ILInstruction>> sections;
int index; int index;
switch (block.Instructions.Count) switch (block.Instructions.Count)
{ {
@ -1286,6 +1287,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!MatchGetChars(@switch.Value, switchValueVar, out index)) if (!MatchGetChars(@switch.Value, switchValueVar, out index))
return false; return false;
sections = @switch.Sections.SelectList(s => new KeyValuePair<LongSet, ILInstruction>(s.Labels, s.Body));
break; break;
case 2: case 2:
if (!block.Instructions[0].MatchStLoc(out var charTempVar, out var getCharsCall)) if (!block.Instructions[0].MatchStLoc(out var charTempVar, out var getCharsCall))
@ -1299,19 +1301,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!@switch.Value.MatchLdLoc(charTempVar)) if (!@switch.Value.MatchLdLoc(charTempVar))
return false; return false;
sections = @switch.Sections.SelectList(s => new KeyValuePair<LongSet, ILInstruction>(s.Labels, s.Body));
break; break;
default: default:
return false; if (!analysis.AnalyzeBlock(block))
{
return false;
}
if (!block.Instructions[0].MatchStLoc(out charTempVar, out getCharsCall))
return false;
if (!MatchGetChars(getCharsCall, switchValueVar, out index))
return false;
if (index < 0)
return false;
if (analysis.SwitchVariable != charTempVar)
return false;
sections = analysis.Sections;
break;
} }
if (index >= length) if (index >= length)
return false; return false;
SwitchSection defaultSection = null; bool hasDefaultSection = false;
foreach (var section in @switch.Sections) foreach (var (labels, body) in sections)
{ {
if (section.Labels.Count() == 1) if (labels.Count() == 1)
{ {
char ch = unchecked((char)section.Labels.Values.Single()); char ch = unchecked((char)labels.Values.Single());
if (!section.Body.MatchBranch(out var targetBlock)) if (!body.MatchBranch(out var targetBlock))
return false; return false;
if (length == 1) if (length == 1)
{ {
@ -1332,9 +1348,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
} }
} }
else if (defaultSection == null) else if (!hasDefaultSection)
{ {
defaultSection = section; hasDefaultSection = true;
} }
else else
{ {
@ -1344,47 +1360,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return results?.Count > 0; return results?.Count > 0;
} }
bool MatchIfElseOnCharBlock(Block startOfChainBlock, int length, ILVariable switchValueVar, out List<(string StringValue, ILInstruction BodyOrLeave)> results)
{
results = null;
if (startOfChainBlock.IncomingEdgeCount != 1)
return false;
if (startOfChainBlock.Instructions.Count != 3)
return false;
if (!startOfChainBlock.Instructions[0].MatchStLoc(out var charTempVar, out var getCharsCall))
return false;
if (!MatchGetChars(getCharsCall, switchValueVar, out int index))
return false;
if (index < 0)
return false;
if (index >= length)
return false;
var currentBlock = startOfChainBlock;
int offset = 1;
while (true)
{
if (!currentBlock.Instructions[offset].MatchIfInstruction(out var condition, out var gotoHead))
break;
if (!condition.MatchCompEquals(out var left, out var right))
break;
if (!left.MatchLdLoc(charTempVar) || !right.MatchLdcI4(out int i))
break;
if (!currentBlock.Instructions[offset + 1].MatchBranch(out var nextBlock))
break;
if (!gotoHead.MatchBranch(out var headBlock))
break;
if (!MatchRoslynCaseBlockHead(headBlock, switchValueVar, out var bodyOrLeave, out var exit, out var stringValue, out _))
break;
if (exit != nullCase)
return false;
results ??= new();
results.Add((stringValue, bodyOrLeave));
offset = 0;
currentBlock = nextBlock;
}
return true;
}
bool MatchSwitchOnLengthBlock(ILVariable switchValueVar, Block switchOnLengthBlock, out List<(LongSet Length, Block TargetBlock)> blocks) bool MatchSwitchOnLengthBlock(ILVariable switchValueVar, Block switchOnLengthBlock, out List<(LongSet Length, Block TargetBlock)> blocks)
{ {
blocks = null; blocks = null;

Loading…
Cancel
Save