Browse Source

Fix #1270: Bad decompilation of mcs switch-on-string

pull/1274/merge
Siegfried Pammer 7 years ago
parent
commit
65cf13ce27
  1. 26
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

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

@ -373,22 +373,30 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary> /// </summary>
bool MatchLegacySwitchOnStringWithDict(InstructionCollection<ILInstruction> instructions, ref int i) bool MatchLegacySwitchOnStringWithDict(InstructionCollection<ILInstruction> instructions, ref int i)
{ {
if (i < 1) return false; // match first block: checking switch-value for null:
// match first block: checking switch-value for null // (In some cases, i.e., if switchValueVar is a parameter, the initial store is optional.)
// stloc switchValueVar(switchValue) // stloc switchValueVar(switchValue)
// if (comp(ldloc switchValueVar == ldnull)) br nullCase // if (comp(ldloc switchValueVar == ldnull)) br nullCase
// br nextBlock // br nextBlock
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)))
return false; return false;
if (!switchValueVar.IsSingleDefinition) if (!(condition.MatchCompEquals(out var left, out var right) && right.MatchLdNull()))
return false;
// The initial store can be omitted in some cases. If there is no initial store or the switch value variable is reused later,
// we do not inline the "switch value", but create an extra load later on.
if (i > 0 && instructions[i - 1].MatchStLoc(out var switchValueVar, out var switchValue)) {
if (!(switchValueVar.IsSingleDefinition && ((SemanticHelper.IsPure(switchValue.Flags) && left.Match(switchValue).Success) || left.MatchLdLoc(switchValueVar))))
return false;
} else {
if (!left.MatchLdLoc(out switchValueVar))
return false;
switchValue = null;
}
if (!switchValueVar.Type.IsKnownType(KnownTypeCode.String))
return false; return false;
// either br nullCase or leave container // either br nullCase or leave container
if (!exitBlockJump.MatchBranch(out var nullValueCaseBlock) && !exitBlockJump.MatchLeave((BlockContainer)instructions[i].Parent.Parent)) if (!exitBlockJump.MatchBranch(out var nullValueCaseBlock) && !exitBlockJump.MatchLeave((BlockContainer)instructions[i].Parent.Parent))
return false; return false;
if (!(condition.MatchCompEquals(out var left, out var right) && right.MatchLdNull()
&& ((SemanticHelper.IsPure(switchValue.Flags) && left.Match(switchValue).Success) || left.MatchLdLoc(switchValueVar))))
return false;
var nextBlockJump = instructions.ElementAtOrDefault(i + 1) as Branch; var nextBlockJump = instructions.ElementAtOrDefault(i + 1) as Branch;
if (nextBlockJump == null || nextBlockJump.TargetBlock.IncomingEdgeCount != 1) if (nextBlockJump == null || nextBlockJump.TargetBlock.IncomingEdgeCount != 1)
return false; return false;
@ -475,7 +483,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
} }
bool keepAssignmentBefore = false; bool keepAssignmentBefore = false;
if (switchValueVar.LoadCount > 2) { if (switchValueVar.LoadCount > 2 || switchValue == null) {
switchValue = new LdLoc(switchValueVar); switchValue = new LdLoc(switchValueVar);
keepAssignmentBefore = true; keepAssignmentBefore = true;
} }

Loading…
Cancel
Save