|
|
@ -19,20 +19,14 @@ |
|
|
|
#nullable enable |
|
|
|
#nullable enable |
|
|
|
|
|
|
|
|
|
|
|
using System; |
|
|
|
using System; |
|
|
|
using System.ComponentModel; |
|
|
|
|
|
|
|
using System.Diagnostics; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Diagnostics.CodeAnalysis; |
|
|
|
using System.Diagnostics.CodeAnalysis; |
|
|
|
using System.Linq; |
|
|
|
using System.Linq; |
|
|
|
using System.Threading; |
|
|
|
|
|
|
|
using System.Xml.Linq; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using ICSharpCode.Decompiler.CSharp.Resolver; |
|
|
|
|
|
|
|
using ICSharpCode.Decompiler.IL.ControlFlow; |
|
|
|
using ICSharpCode.Decompiler.IL.ControlFlow; |
|
|
|
using ICSharpCode.Decompiler.TypeSystem; |
|
|
|
using ICSharpCode.Decompiler.TypeSystem; |
|
|
|
using ICSharpCode.Decompiler.Util; |
|
|
|
using ICSharpCode.Decompiler.Util; |
|
|
|
|
|
|
|
|
|
|
|
using static ICSharpCode.Decompiler.TypeSystem.ReflectionHelper; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
{ |
|
|
|
{ |
|
|
|
class PatternMatchingTransform : IILTransform |
|
|
|
class PatternMatchingTransform : IILTransform |
|
|
@ -110,11 +104,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
pos--; |
|
|
|
pos--; |
|
|
|
} |
|
|
|
} |
|
|
|
if (condition.MatchCompEqualsNull(out var arg)) |
|
|
|
if (condition.MatchCompEqualsNull(out var loadInNullCheck)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ExtensionMethods.Swap(ref trueInst, ref falseInst); |
|
|
|
ExtensionMethods.Swap(ref trueInst, ref falseInst); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (condition.MatchCompNotEqualsNull(out arg)) |
|
|
|
else if (condition.MatchCompNotEqualsNull(out loadInNullCheck)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// do nothing
|
|
|
|
// do nothing
|
|
|
|
} |
|
|
|
} |
|
|
@ -122,7 +116,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
{ |
|
|
|
{ |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
if (!arg.MatchLdLoc(out var s)) |
|
|
|
if (!loadInNullCheck.MatchLdLoc(out var s)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
if (!s.IsSingleDefinition) |
|
|
|
if (!s.IsSingleDefinition) |
|
|
|
return false; |
|
|
|
return false; |
|
|
@ -140,8 +134,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
pos--; |
|
|
|
pos--; |
|
|
|
if (!block.Instructions[pos].MatchStLoc(s, out value)) |
|
|
|
if (!block.Instructions[pos].MatchStLoc(s, out value)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
if (!v.IsSingleDefinition) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
if (v.Kind is not (VariableKind.Local or VariableKind.StackSlot)) |
|
|
|
if (v.Kind is not (VariableKind.Local or VariableKind.StackSlot)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
if (s.LoadCount != 2) |
|
|
|
if (s.LoadCount != 2) |
|
|
@ -172,7 +164,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
|
|
|
|
|
|
|
|
if (!v.Type.Equals(type)) |
|
|
|
if (!v.Type.Equals(type)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
if (!CheckAllUsesDominatedBy(v, container, trueInst, storeToV, context, ref cfg)) |
|
|
|
if (!CheckAllUsesDominatedBy(v, container, trueInst, storeToV, loadInNullCheck, context, ref cfg)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
context.Step($"Type pattern matching {v.Name}", block); |
|
|
|
context.Step($"Type pattern matching {v.Name}", block); |
|
|
|
// if (match.type[T].notnull(V = testedOperand)) br trueBlock
|
|
|
|
// if (match.type[T].notnull(V = testedOperand)) br trueBlock
|
|
|
@ -191,7 +183,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private bool CheckAllUsesDominatedBy(ILVariable v, BlockContainer container, ILInstruction trueInst, |
|
|
|
private bool CheckAllUsesDominatedBy(ILVariable v, BlockContainer container, ILInstruction trueInst, |
|
|
|
ILInstruction storeToV, ILTransformContext context, ref ControlFlowGraph? cfg) |
|
|
|
ILInstruction storeToV, ILInstruction? loadInNullCheck, ILTransformContext context, ref ControlFlowGraph? cfg) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var targetBlock = trueInst as Block; |
|
|
|
var targetBlock = trueInst as Block; |
|
|
|
if (targetBlock == null && !trueInst.MatchBranch(out targetBlock)) |
|
|
|
if (targetBlock == null && !trueInst.MatchBranch(out targetBlock)) |
|
|
@ -203,12 +195,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
cfg ??= new ControlFlowGraph(container, context.CancellationToken); |
|
|
|
cfg ??= new ControlFlowGraph(container, context.CancellationToken); |
|
|
|
var targetBlockNode = cfg.GetNode(targetBlock); |
|
|
|
var targetBlockNode = cfg.GetNode(targetBlock); |
|
|
|
Debug.Assert(v.StoreInstructions.Count == 1); |
|
|
|
|
|
|
|
var uses = v.LoadInstructions.Concat<ILInstruction>(v.AddressInstructions) |
|
|
|
var uses = v.LoadInstructions.Concat<ILInstruction>(v.AddressInstructions) |
|
|
|
.Concat(v.StoreInstructions.Cast<ILInstruction>()); |
|
|
|
.Concat(v.StoreInstructions.Cast<ILInstruction>()); |
|
|
|
foreach (var use in uses) |
|
|
|
foreach (var use in uses) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (use == storeToV) |
|
|
|
if (use == storeToV || use == loadInNullCheck) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
Block? found = null; |
|
|
|
Block? found = null; |
|
|
|
for (ILInstruction? current = use; current != null; current = current.Parent) |
|
|
|
for (ILInstruction? current = use; current != null; current = current.Parent) |
|
|
@ -274,7 +265,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
{ |
|
|
|
{ |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
if (!CheckAllUsesDominatedBy(v, container, unboxBlock, storeToV, context, ref cfg)) |
|
|
|
if (!CheckAllUsesDominatedBy(v, container, unboxBlock, storeToV, null, context, ref cfg)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
context.Step($"PatternMatching with {v.Name}", block); |
|
|
|
context.Step($"PatternMatching with {v.Name}", block); |
|
|
|
var ifInst = (IfInstruction)block.Instructions.SecondToLastOrDefault()!; |
|
|
|
var ifInst = (IfInstruction)block.Instructions.SecondToLastOrDefault()!; |
|
|
|