Browse Source

DetectPinnedRegions: Support special case where pinned pointer is unused and the compiler optimized out the StopGCTracking-conversion.

pull/2642/head
Siegfried Pammer 3 years ago
parent
commit
f98012ec16
  1. 21
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
  2. 9
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  3. 72
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

21
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs

@ -419,13 +419,32 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
UsePointer(ptr); UsePointer(ptr);
} }
} }
#endif
#if CS73
//public unsafe void FixedCustomReferenceType(CustomPinnable mem) //public unsafe void FixedCustomReferenceType(CustomPinnable mem)
//{ //{
// fixed (int* ptr = mem) { // fixed (int* ptr = mem)
// {
// UsePointer(ptr); // 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 #endif
public unsafe string StackAlloc(int count) public unsafe string StackAlloc(int count)

9
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -1168,7 +1168,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
} }
#endregion #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 { static readonly Expression addressOfPinnableReference = new UnaryOperatorExpression {
Operator = UnaryOperatorType.AddressOf, Operator = UnaryOperatorType.AddressOf,
Expression = new InvocationExpression { Expression = new InvocationExpression {
@ -1186,7 +1187,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var m = addressOfPinnableReference.Match(v.Initializer); var m = addressOfPinnableReference.Match(v.Initializer);
if (m.Success) if (m.Success)
{ {
v.Initializer = m.Get<Expression>("target").Single().Detach(); Expression target = m.Get<Expression>("target").Single();
if (target.GetResolveResult().Type.IsReferenceType == false)
{
v.Initializer = target.Detach();
}
} }
} }
} }

72
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) block.Instructions[block.Instructions.Count - 2] = new StLoc(v, gpr)
.WithILRange(block.Instructions[block.Instructions.Count - 2]); .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; ((Branch)block.Instructions.Last()).TargetBlock = targetBlock;
modified = true; modified = true;
} }
@ -235,7 +238,16 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (!block.MatchIfAtEndOfBlock(out var ifCondition, out var trueInst, out var falseInst)) if (!block.MatchIfAtEndOfBlock(out var ifCondition, out var trueInst, out var falseInst))
return false; return false;
if (!ifCondition.MatchCompNotEqualsNull(out ldlocMem)) if (!ifCondition.MatchCompNotEqualsNull(out ldlocMem))
return false; {
if (ifCondition.MatchCompEqualsNull(out ldlocMem))
{
(trueInst, falseInst) = (falseInst, trueInst);
}
else
{
return false;
}
}
if (!SemanticHelper.IsPure(ldlocMem.Flags)) if (!SemanticHelper.IsPure(ldlocMem.Flags))
return false; return false;
if (!trueInst.MatchBranch(out Block notNullBlock) || notNullBlock.Parent != block.Parent) 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) if (!falseInst.MatchBranch(out Block nullBlock) || nullBlock.Parent != block.Parent)
return false; return false;
// Block nullBlock (incoming: 1) {
// stloc ptr(conv i4->u <zero extend>(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) { // Block notNullBlock (incoming: 1) {
// stloc V_1(call GetPinnableReference(ldloc mem)) // stloc V_1(call GetPinnableReference(ldloc mem))
// stloc ptr(conv ref->u (ldloc V_1)) // stloc ptr(conv ref->u (ldloc V_1))
@ -265,7 +262,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// } // }
if (notNullBlock.IncomingEdgeCount != 1) if (notNullBlock.IncomingEdgeCount != 1)
return false; return false;
if (notNullBlock.Instructions.Count != 3) if (notNullBlock.Instructions.Count < 2)
return false; return false;
// stloc V_1(call GetPinnableReference(ldloc mem)) // stloc V_1(call GetPinnableReference(ldloc mem))
if (!notNullBlock.Instructions[0].MatchStLoc(out v, out var value)) if (!notNullBlock.Instructions[0].MatchStLoc(out v, out var value))
@ -281,13 +278,38 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return false; return false;
// stloc ptr(conv ref->u (ldloc V_1)) // stloc ptr(conv ref->u (ldloc V_1))
ptrAssign = notNullBlock.Instructions[1] as StLoc; ptrAssign = notNullBlock.Instructions[1] as StLoc;
if (ptrAssign == null || ptrAssign.Variable != ptr) if (ptrAssign != null)
return false; {
if (!ptrAssign.Value.UnwrapConv(ConversionKind.StopGCTracking).MatchLdLoc(v)) if (!ptrAssign.Value.UnwrapConv(ConversionKind.StopGCTracking).MatchLdLoc(v))
return false; return false;
// br targetBlock // br targetBlock
if (!notNullBlock.Instructions[2].MatchBranch(targetBlock)) if (!notNullBlock.Instructions[2].MatchBranch(out targetBlock))
return false; return false;
// Block nullBlock (incoming: 1) {
// stloc ptr(conv i4->u <zero extend>(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; return true;
} }

Loading…
Cancel
Save