From b3bc0a71e26e83b851c903bc5ed946489c83d231 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 7 Sep 2020 01:30:42 +0800 Subject: [PATCH] Add unsigned overloads for Unsafe Add/Subtract and Add/SubtractByteOffset (#40715) * Implement unsigned reference math in IL. * Update reference source for Unsafe. * Copy docs to UIntPtr overloads. * Add tests for UIntPtr. * Use nuint instead of UIntPtr. * Fix reference to CORE_ASSEMBLY. --- .../ref/System.Runtime.CompilerServices.Unsafe.cs | 4 + .../src/System.Runtime.CompilerServices.Unsafe.il | 129 +++++++++++++++++++++ .../src/System.Runtime.CompilerServices.Unsafe.xml | 36 ++++++ .../tests/UnsafeTests.cs | 42 +++++++ 4 files changed, 211 insertions(+) diff --git a/src/libraries/System.Runtime.CompilerServices.Unsafe/ref/System.Runtime.CompilerServices.Unsafe.cs b/src/libraries/System.Runtime.CompilerServices.Unsafe/ref/System.Runtime.CompilerServices.Unsafe.cs index 319ca07..be4b8ed 100644 --- a/src/libraries/System.Runtime.CompilerServices.Unsafe/ref/System.Runtime.CompilerServices.Unsafe.cs +++ b/src/libraries/System.Runtime.CompilerServices.Unsafe/ref/System.Runtime.CompilerServices.Unsafe.cs @@ -9,9 +9,11 @@ namespace System.Runtime.CompilerServices public static partial class Unsafe { public static ref T AddByteOffset(ref T source, System.IntPtr byteOffset) { throw null; } + public static ref T AddByteOffset(ref T source, nuint byteOffset) { throw null; } public unsafe static void* Add(void* source, int elementOffset) { throw null; } public static ref T Add(ref T source, int elementOffset) { throw null; } public static ref T Add(ref T source, System.IntPtr elementOffset) { throw null; } + public static ref T Add(ref T source, nuint elementOffset) { throw null; } public static bool AreSame([System.Diagnostics.CodeAnalysis.AllowNull] ref T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref T right) { throw null; } public unsafe static void* AsPointer(ref T value) { throw null; } public unsafe static ref T AsRef(void* source) { throw null; } @@ -42,9 +44,11 @@ namespace System.Runtime.CompilerServices public static void SkipInit(out T value) { throw null; } public static int SizeOf() { throw null; } public static ref T SubtractByteOffset(ref T source, System.IntPtr byteOffset) { throw null; } + public static ref T SubtractByteOffset(ref T source, nuint byteOffset) { throw null; } public unsafe static void* Subtract(void* source, int elementOffset) { throw null; } public static ref T Subtract(ref T source, int elementOffset) { throw null; } public static ref T Subtract(ref T source, System.IntPtr elementOffset) { throw null; } + public static ref T Subtract(ref T source, nuint elementOffset) { throw null; } public static ref T Unbox(object box) where T : struct { throw null; } public static void WriteUnaligned(ref byte destination, T value) { } public unsafe static void WriteUnaligned(void* destination, T value) { } diff --git a/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il b/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il index ded3c71..c746a05 100644 --- a/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il +++ b/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il @@ -360,6 +360,22 @@ ret } // end of method Unsafe::Add + .method public hidebysig static !!T& Add(!!T& source, native uint elementOffset) cil managed aggressiveinlining + { + .param [2] + .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 3 + ldarg.0 + ldarg.1 + sizeof !!T + mul + add + ret + } // end of method Unsafe::Add + .method public hidebysig static !!T& AddByteOffset(!!T& source, native int byteOffset) cil managed aggressiveinlining { .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) @@ -370,6 +386,20 @@ ret } // end of method Unsafe::AddByteOffset + .method public hidebysig static !!T& AddByteOffset(!!T& source, native uint byteOffset) cil managed aggressiveinlining + { + .param [2] + .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 2 + ldarg.0 + ldarg.1 + add + ret + } // end of method Unsafe::AddByteOffset + .method public hidebysig static !!T& Subtract(!!T& source, int32 elementOffset) cil managed aggressiveinlining { .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) @@ -408,6 +438,22 @@ ret } // end of method Unsafe::Subtract + .method public hidebysig static !!T& Subtract(!!T& source, native uint elementOffset) cil managed aggressiveinlining + { + .param [2] + .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 3 + ldarg.0 + ldarg.1 + sizeof !!T + mul + sub + ret + } // end of method Unsafe::Subtract + .method public hidebysig static !!T& SubtractByteOffset(!!T& source, native int byteOffset) cil managed aggressiveinlining { .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) @@ -418,6 +464,20 @@ ret } // end of method Unsafe::SubtractByteOffset + .method public hidebysig static !!T& SubtractByteOffset(!!T& source, native uint byteOffset) cil managed aggressiveinlining + { + .param [2] + .custom instance void System.Runtime.CompilerServices.NativeIntegerAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 2 + ldarg.0 + ldarg.1 + sub + ret + } // end of method Unsafe::SubtractByteOffset + .method public hidebysig static native int ByteOffset(!!T& origin, !!T& target) cil managed aggressiveinlining { .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) @@ -513,3 +573,72 @@ } // end of class System.Runtime.CompilerServices.IsReadOnlyAttribute #endif + +.class private auto ansi sealed beforefieldinit Microsoft.CodeAnalysis.EmbeddedAttribute + extends [CORE_ASSEMBLY]System.Attribute +{ + .custom instance void [CORE_ASSEMBLY]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( + 01 00 00 00 + ) + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [CORE_ASSEMBLY]System.Attribute::.ctor() + IL_0006: ret + } // end of method EmbeddedAttribute::.ctor + +} // end of class Microsoft.CodeAnalysis.EmbeddedAttribute + +.class private auto ansi sealed beforefieldinit System.Runtime.CompilerServices.NativeIntegerAttribute + extends [CORE_ASSEMBLY]System.Attribute +{ + .custom instance void [CORE_ASSEMBLY]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [CORE_ASSEMBLY]System.AttributeUsageAttribute::.ctor(valuetype [CORE_ASSEMBLY]System.AttributeTargets) = ( + 01 00 84 6b 00 00 02 00 54 02 0d 41 6c 6c 6f 77 + 4d 75 6c 74 69 70 6c 65 00 54 02 09 49 6e 68 65 + 72 69 74 65 64 00 + ) + .field public initonly bool[] TransformFlags + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [CORE_ASSEMBLY]System.Attribute::.ctor() + IL_0006: ldarg.0 + IL_0007: ldc.i4.1 + IL_0008: newarr [CORE_ASSEMBLY]System.Boolean + IL_000d: dup + IL_000e: ldc.i4.0 + IL_000f: ldc.i4.1 + IL_0010: stelem.i1 + IL_0011: stfld bool[] System.Runtime.CompilerServices.NativeIntegerAttribute::TransformFlags + IL_0016: ret + } // end of method NativeIntegerAttribute::.ctor + + .method public hidebysig specialname rtspecialname + instance void .ctor ( + bool[] '' + ) cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [CORE_ASSEMBLY]System.Attribute::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld bool[] System.Runtime.CompilerServices.NativeIntegerAttribute::TransformFlags + IL_000d: ret + } // end of method NativeIntegerAttribute::.ctor + +} // end of class System.Runtime.CompilerServices.NativeIntegerAttribute diff --git a/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.xml b/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.xml index 1979a5c..7acab80 100644 --- a/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.xml +++ b/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.xml @@ -156,6 +156,15 @@ The offset to add. A new reference that reflects the addition of offset to pointer. + + + Adds an element offset to the given reference. + + The type of reference. + The reference to add the offset to. + The offset to add. + A new reference that reflects the addition of offset to pointer. + Adds a byte offset to the given reference. @@ -165,6 +174,15 @@ The offset to add. A new reference that reflects the addition of byte offset to pointer. + + + Adds a byte offset to the given reference. + + The type of reference. + The reference to add the offset to. + The offset to add. + A new reference that reflects the addition of byte offset to pointer. + Subtracts an element offset from the given reference. @@ -183,6 +201,15 @@ The offset to subtract. A new reference that reflects the subraction of offset from pointer. + + + Subtracts an element offset from the given reference. + + The type of reference. + The reference to subtract the offset from. + The offset to subtract. + A new reference that reflects the subraction of offset from pointer. + Subtracts a byte offset from the given reference. @@ -192,6 +219,15 @@ The offset to subtract. A new reference that reflects the subraction of byte offset from pointer. + + + Subtracts a byte offset from the given reference. + + The type of reference. + The reference to subtract the offset from. + The offset to subtract. + A new reference that reflects the subraction of byte offset from pointer. + Determines the byte offset from origin to target from the given references. diff --git a/src/libraries/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs b/src/libraries/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs index 34b0140..b2c811c 100644 --- a/src/libraries/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs +++ b/src/libraries/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs @@ -505,6 +505,18 @@ namespace System.Runtime.CompilerServices } [Fact] + public static void RefAddNuint() + { + int[] a = new int[] { 0x123, 0x234, 0x345, 0x456 }; + + ref int r1 = ref Unsafe.Add(ref a[0], (nuint)1); + Assert.Equal(0x234, r1); + + ref int r2 = ref Unsafe.Add(ref r1, (nuint)2); + Assert.Equal(0x456, r2); + } + + [Fact] public static void RefAddByteOffset() { byte[] a = new byte[] { 0x12, 0x34, 0x56, 0x78 }; @@ -520,6 +532,18 @@ namespace System.Runtime.CompilerServices } [Fact] + public static void RefAddNuintByteOffset() + { + byte[] a = new byte[] { 0x12, 0x34, 0x56, 0x78 }; + + ref byte r1 = ref Unsafe.AddByteOffset(ref a[0], (nuint)1); + Assert.Equal(0x34, r1); + + ref byte r2 = ref Unsafe.AddByteOffset(ref r1, (nuint)2); + Assert.Equal(0x78, r2); + } + + [Fact] public static void RefSubtract() { string[] a = new string[] { "abc", "def", "ghi", "jkl" }; @@ -577,6 +601,15 @@ namespace System.Runtime.CompilerServices } [Fact] + public static void RefSubtractNuint() + { + string[] a = new string[] { "abc", "def", "ghi", "jkl" }; + + ref string r3 = ref Unsafe.Subtract(ref a[3], (nuint)3); + Assert.Equal("abc", r3); + } + + [Fact] public static void RefSubtractByteOffset() { byte[] a = new byte[] { 0x12, 0x34, 0x56, 0x78 }; @@ -592,6 +625,15 @@ namespace System.Runtime.CompilerServices } [Fact] + public static void RefSubtractNuintByteOffset() + { + byte[] a = new byte[] { 0x12, 0x34, 0x56, 0x78 }; + + ref byte r3 = ref Unsafe.SubtractByteOffset(ref a[3], (nuint)3); + Assert.Equal(0x12, r3); + } + + [Fact] public static void RefAreSame() { long[] a = new long[2]; -- 2.7.4