From f98012ec16dee4472407d7d1a0c0694f9a9bf1c9 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 5 Mar 2022 16:51:09 +0100 Subject: [PATCH] DetectPinnedRegions: Support special case where pinned pointer is unused and the compiler optimized out the StopGCTracking-conversion. --- .../TestCases/Pretty/UnsafeCode.cs | 21 +++++- .../Transforms/PatternStatementTransform.cs | 9 ++- .../IL/ControlFlow/DetectPinnedRegions.cs | 72 ++++++++++++------- 3 files changed, 74 insertions(+), 28 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs index d24744dc7..cdf4f52d8 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs @@ -419,13 +419,32 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty UsePointer(ptr); } } +#endif +#if CS73 //public unsafe void FixedCustomReferenceType(CustomPinnable mem) //{ - // fixed (int* ptr = mem) { + // fixed (int* ptr = mem) + // { // UsePointer(ptr); // } //} + + public unsafe void FixedCustomReferenceTypeNoPointerUse(CustomPinnable mem) + { + fixed (int* ptr = mem) + { + Console.WriteLine("Hello World!"); + } + } + + public unsafe void FixedCustomReferenceTypeExplicitGetPinnableReference(CustomPinnable mem) + { + fixed (int* ptr = &mem.GetPinnableReference()) + { + UsePointer(ptr); + } + } #endif public unsafe string StackAlloc(int count) diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs index 006f4c562..56af46797 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs @@ -1168,7 +1168,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms } #endregion - #region C# 7.3 pattern based fixed + #region C# 7.3 pattern based fixed (for value types) + // reference types are handled by DetectPinnedRegions.IsCustomRefPinPattern static readonly Expression addressOfPinnableReference = new UnaryOperatorExpression { Operator = UnaryOperatorType.AddressOf, Expression = new InvocationExpression { @@ -1186,7 +1187,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms var m = addressOfPinnableReference.Match(v.Initializer); if (m.Success) { - v.Initializer = m.Get("target").Single().Detach(); + Expression target = m.Get("target").Single(); + if (target.GetResolveResult().Type.IsReferenceType == false) + { + v.Initializer = target.Detach(); + } } } } diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs b/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs index 24cbea9e4..4a6de77b1 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs @@ -192,7 +192,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow } block.Instructions[block.Instructions.Count - 2] = new StLoc(v, gpr) .WithILRange(block.Instructions[block.Instructions.Count - 2]); - block.Instructions.Insert(block.Instructions.Count - 1, stlocPtr); + if (stlocPtr != null) + { + block.Instructions.Insert(block.Instructions.Count - 1, stlocPtr); + } ((Branch)block.Instructions.Last()).TargetBlock = targetBlock; modified = true; } @@ -235,7 +238,16 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow if (!block.MatchIfAtEndOfBlock(out var ifCondition, out var trueInst, out var falseInst)) return false; if (!ifCondition.MatchCompNotEqualsNull(out ldlocMem)) - return false; + { + if (ifCondition.MatchCompEqualsNull(out ldlocMem)) + { + (trueInst, falseInst) = (falseInst, trueInst); + } + else + { + return false; + } + } if (!SemanticHelper.IsPure(ldlocMem.Flags)) return false; if (!trueInst.MatchBranch(out Block notNullBlock) || notNullBlock.Parent != block.Parent) @@ -243,21 +255,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow if (!falseInst.MatchBranch(out Block nullBlock) || nullBlock.Parent != block.Parent) return false; - // Block nullBlock (incoming: 1) { - // stloc ptr(conv i4->u (ldc.i4 0)) - // br targetBlock - // } - if (nullBlock.IncomingEdgeCount != 1) - return false; - if (nullBlock.Instructions.Count != 2) - return false; - if (!nullBlock.Instructions[0].MatchStLoc(out var ptr, out var nullPointerInst)) - return false; - if (!nullPointerInst.MatchLdcI(0)) - return false; - if (!nullBlock.Instructions[1].MatchBranch(out targetBlock)) - return false; - // Block notNullBlock (incoming: 1) { // stloc V_1(call GetPinnableReference(ldloc mem)) // stloc ptr(conv ref->u (ldloc V_1)) @@ -265,7 +262,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow // } if (notNullBlock.IncomingEdgeCount != 1) return false; - if (notNullBlock.Instructions.Count != 3) + if (notNullBlock.Instructions.Count < 2) return false; // stloc V_1(call GetPinnableReference(ldloc mem)) if (!notNullBlock.Instructions[0].MatchStLoc(out v, out var value)) @@ -281,13 +278,38 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow return false; // stloc ptr(conv ref->u (ldloc V_1)) ptrAssign = notNullBlock.Instructions[1] as StLoc; - if (ptrAssign == null || ptrAssign.Variable != ptr) - return false; - if (!ptrAssign.Value.UnwrapConv(ConversionKind.StopGCTracking).MatchLdLoc(v)) - return false; - // br targetBlock - if (!notNullBlock.Instructions[2].MatchBranch(targetBlock)) - return false; + if (ptrAssign != null) + { + if (!ptrAssign.Value.UnwrapConv(ConversionKind.StopGCTracking).MatchLdLoc(v)) + return false; + // br targetBlock + if (!notNullBlock.Instructions[2].MatchBranch(out targetBlock)) + return false; + + // Block nullBlock (incoming: 1) { + // stloc ptr(conv i4->u (ldc.i4 0)) + // br targetBlock + // } + if (nullBlock.IncomingEdgeCount != 1) + return false; + if (nullBlock.Instructions.Count != 2) + return false; + if (!nullBlock.Instructions[0].MatchStLoc(ptrAssign.Variable, out var nullPointerInst)) + return false; + if (!nullPointerInst.MatchLdcI(0)) + return false; + if (!nullBlock.Instructions[1].MatchBranch(targetBlock)) + return false; + } + else + { + // br targetBlock + if (!notNullBlock.Instructions[1].MatchBranch(out targetBlock)) + return false; + + if (targetBlock != nullBlock) + return false; + } return true; }