Browse Source

Simplify SwitchOnNullableTransform.

pull/887/head
Daniel Grunwald 8 years ago
parent
commit
6272c21ece
  1. 41
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
  2. 53
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnNullableTransform.cs
  3. 2
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

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

@ -102,7 +102,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
#region AnalyzeCondition #region AnalyzeCondition
bool AnalyzeCondition(ILInstruction condition) bool AnalyzeCondition(ILInstruction condition)
{ {
if (MatchHasValueCall(condition, out var v)) { if (MatchHasValueCall(condition, out ILVariable v)) {
if (nullableVars == null) if (nullableVars == null)
nullableVars = new List<ILVariable>(); nullableVars = new List<ILVariable>();
nullableVars.Add(v); nullableVars.Add(v);
@ -387,9 +387,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// Comparing two nullables: HasValue comparison must be the same operator as the Value comparison // Comparing two nullables: HasValue comparison must be the same operator as the Value comparison
if ((hasValueTestNegated ? hasValueComp.Kind.Negate() : hasValueComp.Kind) != newComparisonKind) if ((hasValueTestNegated ? hasValueComp.Kind.Negate() : hasValueComp.Kind) != newComparisonKind)
return null; return null;
if (!MatchHasValueCall(hasValueComp.Left, out var leftVar)) if (!MatchHasValueCall(hasValueComp.Left, out ILVariable leftVar))
return null; return null;
if (!MatchHasValueCall(hasValueComp.Right, out var rightVar)) if (!MatchHasValueCall(hasValueComp.Right, out ILVariable rightVar))
return null; return null;
nullableVars = new List<ILVariable> { leftVar }; nullableVars = new List<ILVariable> { leftVar };
var (left, leftBits) = DoLift(valueComp.Left); var (left, leftBits) = DoLift(valueComp.Left);
@ -401,7 +401,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step("NullableLiftingTransform: C# (in)equality comparison", valueComp.Instruction); context.Step("NullableLiftingTransform: C# (in)equality comparison", valueComp.Instruction);
return valueComp.MakeLifted(newComparisonKind, left, right); return valueComp.MakeLifted(newComparisonKind, left, right);
} }
} else if (newComparisonKind == ComparisonKind.Equality && !hasValueTestNegated && MatchHasValueCall(hasValueTest, out var v)) { } else if (newComparisonKind == ComparisonKind.Equality && !hasValueTestNegated && MatchHasValueCall(hasValueTest, out ILVariable v)) {
// Comparing nullable with non-nullable -> we can fall back to the normal comparison code. // Comparing nullable with non-nullable -> we can fall back to the normal comparison code.
nullableVars = new List<ILVariable> { v }; nullableVars = new List<ILVariable> { v };
return LiftCSharpComparison(valueComp, newComparisonKind); return LiftCSharpComparison(valueComp, newComparisonKind);
@ -461,13 +461,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// else // else
// ldc.i4 0 // ldc.i4 0
if (!MatchHasValueCall(hasValueComp.Left, out var nullable1)) if (!MatchHasValueCall(hasValueComp.Left, out ILVariable nullable1))
return null; return null;
if (!MatchHasValueCall(hasValueComp.Right, out var nullable2)) if (!MatchHasValueCall(hasValueComp.Right, out ILVariable nullable2))
return null; return null;
if (!nestedIfInst.MatchIfInstructionPositiveCondition(out var condition, out var trueInst, out var falseInst)) if (!nestedIfInst.MatchIfInstructionPositiveCondition(out var condition, out var trueInst, out var falseInst))
return null; return null;
if (!MatchHasValueCall(condition, out var nullable)) if (!MatchHasValueCall(condition, out ILVariable nullable))
return null; return null;
if (nullable != nullable1 && nullable != nullable2) if (nullable != nullable1 && nullable != nullable2)
return null; return null;
@ -516,7 +516,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (trueInst.MatchIfInstructionPositiveCondition(out var nestedCondition, out var nestedTrue, out var nestedFalse)) { if (trueInst.MatchIfInstructionPositiveCondition(out var nestedCondition, out var nestedTrue, out var nestedFalse)) {
// Sometimes Roslyn generates pointless conditions like: // Sometimes Roslyn generates pointless conditions like:
// if (nullable.HasValue && (!nullable.HasValue || nullable.GetValueOrDefault() == b)) // if (nullable.HasValue && (!nullable.HasValue || nullable.GetValueOrDefault() == b))
if (MatchHasValueCall(nestedCondition, out var v) && nullableVars.Contains(v)) { if (MatchHasValueCall(nestedCondition, out ILVariable v) && nullableVars.Contains(v)) {
trueInst = nestedTrue; trueInst = nestedTrue;
} }
} }
@ -758,11 +758,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
#region Match...Call #region Match...Call
/// <summary> /// <summary>
/// Matches 'call get_HasValue(ldloca v)' /// Matches 'call get_HasValue(arg)'
/// </summary> /// </summary>
internal static bool MatchHasValueCall(ILInstruction inst, out ILVariable v) internal static bool MatchHasValueCall(ILInstruction inst, out ILInstruction arg)
{ {
v = null; arg = null;
if (!(inst is Call call)) if (!(inst is Call call))
return false; return false;
if (call.Arguments.Count != 1) if (call.Arguments.Count != 1)
@ -771,7 +771,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (call.Method.DeclaringTypeDefinition?.KnownTypeCode != KnownTypeCode.NullableOfT) if (call.Method.DeclaringTypeDefinition?.KnownTypeCode != KnownTypeCode.NullableOfT)
return false; return false;
return call.Arguments[0].MatchLdLoca(out v); arg = call.Arguments[0];
return true;
}
/// <summary>
/// Matches 'call get_HasValue(ldloca v)'
/// </summary>
internal static bool MatchHasValueCall(ILInstruction inst, out ILVariable v)
{
if (MatchHasValueCall(inst, out ILInstruction arg)) {
return arg.MatchLdLoca(out v);
}
v = null;
return false;
} }
/// <summary> /// <summary>
@ -779,7 +792,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary> /// </summary>
internal static bool MatchHasValueCall(ILInstruction inst, ILVariable v) internal static bool MatchHasValueCall(ILInstruction inst, ILVariable v)
{ {
return MatchHasValueCall(inst, out var v2) && v == v2; return MatchHasValueCall(inst, out ILVariable v2) && v == v2;
} }
/// <summary> /// <summary>
@ -811,7 +824,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// <summary> /// <summary>
/// Matches 'call Nullable{T}.GetValueOrDefault(arg)' /// Matches 'call Nullable{T}.GetValueOrDefault(arg)'
/// </summary> /// </summary>
static bool MatchGetValueOrDefault(ILInstruction inst, out ILInstruction arg) internal static bool MatchGetValueOrDefault(ILInstruction inst, out ILInstruction arg)
{ {
arg = null; arg = null;
if (!(inst is Call call)) if (!(inst is Call call))

53
ICSharpCode.Decompiler/IL/Transforms/SwitchOnNullableTransform.cs

@ -92,15 +92,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!condition.MatchLogicNot(out var getHasValue)) if (!condition.MatchLogicNot(out var getHasValue))
return false; return false;
if (!(getValueOrDefault is Call getValueOrDefaultCall) || getValueOrDefaultCall.Method.FullName != "System.Nullable.GetValueOrDefault" || if (!NullableLiftingTransform.MatchGetValueOrDefault(getValueOrDefault, out ILInstruction getValueOrDefaultArg))
getValueOrDefaultCall.Method.DeclaringType.TypeParameterCount != 1)
return false; return false;
if (!(getHasValue is Call getHasValueCall) || !getHasValueCall.Method.IsAccessor || getHasValueCall.Method.FullName != "System.Nullable.get_HasValue" || if (!NullableLiftingTransform.MatchHasValueCall(getHasValue, out ILInstruction getHasValueArg))
getHasValueCall.Method.DeclaringType.TypeParameterCount != 1)
return false; return false;
if (getHasValueCall.Arguments.Count != 1 || getValueOrDefaultCall.Arguments.Count != 1) if (!(getHasValueArg.MatchLdLoc(tmp) && getValueOrDefaultArg.MatchLdLoc(tmp)))
return false;
if (!getHasValueCall.Arguments[0].MatchLdLoc(tmp) || !getValueOrDefaultCall.Arguments[0].MatchLdLoc(tmp))
return false; return false;
// match second block: switchBlock // match second block: switchBlock
// switch (ldloc switchVariable) { // switch (ldloc switchVariable) {
@ -112,22 +108,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!(switchBlock.Instructions[0] is SwitchInstruction switchInst)) if (!(switchBlock.Instructions[0] is SwitchInstruction switchInst))
return false; return false;
newSwitch = new SwitchInstruction(new LdLoc(switchValueVar)); newSwitch = BuildLiftedSwitch(nullCaseBlock, switchInst, new LdLoc(switchValueVar));
newSwitch.IsLifted = true;
SwitchSection defaultSection = null;
foreach (var section in switchInst.Sections) {
if (defaultSection == null || section.Labels.Count() >= defaultSection.Labels.Count())
defaultSection = section;
newSwitch.Sections.Add(section);
}
if (defaultSection.Body.MatchBranch(out var defaultBlock) && defaultBlock == nullCaseBlock)
defaultSection.HasNullLabel = true;
else {
newSwitch.Sections.Add(new SwitchSection { Body = new Branch(nullCaseBlock), HasNullLabel = true });
}
return true; return true;
} }
static SwitchInstruction BuildLiftedSwitch(Block nullCaseBlock, SwitchInstruction switchInst, ILInstruction switchValue)
{
SwitchInstruction newSwitch = new SwitchInstruction(switchValue);
newSwitch.IsLifted = true;
newSwitch.Sections.AddRange(switchInst.Sections);
newSwitch.Sections.Add(new SwitchSection { Body = new Branch(nullCaseBlock), HasNullLabel = true });
return newSwitch;
}
/// <summary> /// <summary>
/// Matches Roslyn C# switch on nullable. /// Matches Roslyn C# switch on nullable.
/// </summary> /// </summary>
@ -142,11 +135,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!instructions[i - 1].MatchStLoc(out var tmp, out var switchValue) || if (!instructions[i - 1].MatchStLoc(out var tmp, out var switchValue) ||
!instructions[i].MatchIfInstruction(out var condition, out var trueInst)) !instructions[i].MatchIfInstruction(out var condition, out var trueInst))
return false; return false;
if (tmp.StoreCount != 1 || tmp.AddressCount != 2) if (tmp.StoreCount != 1 || tmp.AddressCount != 2 || tmp.LoadCount != 0)
return false; return false;
if (!instructions[i + 1].MatchBranch(out var switchBlock) || !trueInst.MatchBranch(out var nullCaseBlock)) if (!instructions[i + 1].MatchBranch(out var switchBlock) || !trueInst.MatchBranch(out var nullCaseBlock))
return false; return false;
if (!condition.MatchLogicNot(out var getHasValue) || !NullableLiftingTransform.MatchHasValueCall(getHasValue, out var target1) || target1 != tmp) if (!condition.MatchLogicNot(out var getHasValue) || !NullableLiftingTransform.MatchHasValueCall(getHasValue, out ILVariable target1) || target1 != tmp)
return false; return false;
// match second block: switchBlock // match second block: switchBlock
// stloc switchVar(call GetValueOrDefault(ldloca tmp)) // stloc switchVar(call GetValueOrDefault(ldloca tmp))
@ -161,23 +154,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!switchVar.IsSingleDefinition || switchVar.LoadCount != 1) if (!switchVar.IsSingleDefinition || switchVar.LoadCount != 1)
return false; return false;
if (!NullableLiftingTransform.MatchGetValueOrDefault(getValueOrDefault, out var target2) || target2 != tmp) if (!NullableLiftingTransform.MatchGetValueOrDefault(getValueOrDefault, tmp))
return false; return false;
if (!(switchBlock.Instructions[1] is SwitchInstruction switchInst)) if (!(switchBlock.Instructions[1] is SwitchInstruction switchInst))
return false; return false;
newSwitch = new SwitchInstruction(switchValue); newSwitch = BuildLiftedSwitch(nullCaseBlock, switchInst, switchValue);
newSwitch.IsLifted = true;
SwitchSection defaultSection = null;
foreach (var section in switchInst.Sections) {
if (defaultSection == null || section.Labels.Count() >= defaultSection.Labels.Count())
defaultSection = section;
newSwitch.Sections.Add(section);
}
if (defaultSection.Body.MatchBranch(out var defaultBlock) && defaultBlock == nullCaseBlock)
defaultSection.HasNullLabel = true;
else {
newSwitch.Sections.Add(new SwitchSection { Body = new Branch(nullCaseBlock), HasNullLabel = true });
}
return true; return true;
} }
} }

2
ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

@ -188,7 +188,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (objVar.Type.IsKnownType(KnownTypeCode.NullableOfT)) { if (objVar.Type.IsKnownType(KnownTypeCode.NullableOfT)) {
if (!entryPoint.Instructions[checkIndex].MatchIfInstruction(out var condition, out var disposeInst)) if (!entryPoint.Instructions[checkIndex].MatchIfInstruction(out var condition, out var disposeInst))
return false; return false;
if (!(NullableLiftingTransform.MatchHasValueCall(condition, out var v) && v == objVar)) if (!NullableLiftingTransform.MatchHasValueCall(condition, objVar))
return false; return false;
if (!(disposeInst is Block disposeBlock) || disposeBlock.Instructions.Count != 1) if (!(disposeInst is Block disposeBlock) || disposeBlock.Instructions.Count != 1)
return false; return false;

Loading…
Cancel
Save