Browse Source

Use `Unsafe.AsPointer()` for `ConversionKind.StopGCTracking`.

pull/2045/head
Daniel Grunwald 5 years ago
parent
commit
a0b144d332
  1. 7
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs
  2. 8
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.il
  3. 14
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  4. 18
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
  5. 17
      ICSharpCode.Decompiler/IL/PointerArithmeticOffset.cs

7
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs

@ -20,6 +20,11 @@ internal sealed class ExtraUnsafeTests @@ -20,6 +20,11 @@ internal sealed class ExtraUnsafeTests
fixed (ushort* ptr = &Unsafe.As<uint, ushort>(ref managedPtr)) {
}
}
public unsafe static uint* RefToPointerWithoutPinning(ref uint managedPtr)
{
return (uint*)Unsafe.AsPointer(ref managedPtr);
}
}
namespace System.Runtime.CompilerServices
@ -77,7 +82,7 @@ namespace System.Runtime.CompilerServices @@ -77,7 +82,7 @@ namespace System.Runtime.CompilerServices
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static void* AsPointer<T>(ref T value)
{
return &value;
return Unsafe.AsPointer(ref value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

8
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.il

@ -466,4 +466,12 @@ @@ -466,4 +466,12 @@
ret
}
.method public hidebysig static uint32* RefToPointerWithoutPinning(uint32& managedPtr)
{
.maxstack 8
ldarg.0
ret
}
}

14
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1676,9 +1676,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1676,9 +1676,17 @@ namespace ICSharpCode.Decompiler.CSharp
return arg;
case ConversionKind.StopGCTracking:
if (inputType.Kind == TypeKind.ByReference) {
// cast to corresponding pointer type:
var pointerType = new PointerType(((ByReferenceType)inputType).ElementType);
return arg.ConvertTo(pointerType, this).WithILInstruction(inst);
if (PointerArithmeticOffset.IsFixedVariable(inst.Argument)) {
// cast to corresponding pointer type:
var pointerType = new PointerType(((ByReferenceType)inputType).ElementType);
return arg.ConvertTo(pointerType, this).WithILInstruction(inst);
} else {
// emit Unsafe.AsPointer() intrinsic:
return CallUnsafeIntrinsic("AsPointer",
arguments: new Expression[] { arg },
returnType: new PointerType(compilation.FindType(KnownTypeCode.Void)),
inst: inst);
}
} else if (arg.Type.GetStackType().IsIntegerType()) {
// ConversionKind.StopGCTracking should only be used with managed references,
// but it's possible that we're supposed to stop tracking something we just started to track.

18
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -488,28 +488,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -488,28 +488,12 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (this.Expression is DirectionExpression dirExpr) {
var inst = dirExpr.Expression.Annotation<ILInstruction>();
return inst != null && IsFixedVariable(inst);
return inst != null && PointerArithmeticOffset.IsFixedVariable(inst);
} else {
return false;
}
}
/// <summary>
/// Returns true if <c>inst</c> computes the address of a fixed variable; false if it computes the address of a moveable variable.
/// (see "Fixed and moveable variables" in the C# specification)
/// </summary>
static bool IsFixedVariable(ILInstruction inst)
{
switch (inst) {
case LdLoca ldloca:
return ldloca.Variable.CaptureScope == null; // locals are fixed if uncaptured
case LdFlda ldflda:
return IsFixedVariable(ldflda.Target);
default:
return inst.ResultType == StackType.I;
}
}
/// <summary>
/// Gets whether an implicit conversion from 'inputType' to 'newTargetType'
/// would have the same semantics as the existing cast from 'inputType' to 'oldTargetType'.

17
ICSharpCode.Decompiler/IL/PointerArithmeticOffset.cs

@ -82,5 +82,22 @@ namespace ICSharpCode.Decompiler.IL @@ -82,5 +82,22 @@ namespace ICSharpCode.Decompiler.IL
}
return null;
}
/// <summary>
/// Returns true if <c>inst</c> computes the address of a fixed variable; false if it computes the address of a moveable variable.
/// (see "Fixed and moveable variables" in the C# specification)
/// </summary>
internal static bool IsFixedVariable(ILInstruction inst)
{
switch (inst) {
case LdLoca ldloca:
return ldloca.Variable.CaptureScope == null; // locals are fixed if uncaptured
case LdFlda ldflda:
return IsFixedVariable(ldflda.Target);
default:
return inst.ResultType == StackType.I;
}
}
}
}

Loading…
Cancel
Save