From b6275048e66b8e51ee8c3c8f444e3c64d0f3a4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E4=BB=99=E5=A5=B3?= Date: Mon, 26 Dec 2022 16:04:08 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E7=BB=99=E7=B1=BB=E5=8A=A0=E4=B8=8A?= =?UTF-8?q?=E4=BA=86unsafe,=20=E5=8E=BB=E9=99=A4=E4=BA=86=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E4=B8=AD=E7=9A=84unsafe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UnsafeHelper/UnsafeHelper.cs | 68 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/UnsafeHelper/UnsafeHelper.cs b/UnsafeHelper/UnsafeHelper.cs index 6bb6be2..44b5a44 100644 --- a/UnsafeHelper/UnsafeHelper.cs +++ b/UnsafeHelper/UnsafeHelper.cs @@ -10,13 +10,13 @@ namespace IlyfairyLib.Unsafe /// /// Unsafe的工具方法 /// - public static class UnsafeHelper + public static unsafe class UnsafeHelper { private static readonly Type RuntimeHelpersType; private static readonly Func? AllocateUninitializedClone; private static readonly int m_fieldHandle_offset = -1; // RtFieldInfo中的m_fieldHandle的偏移地址 - unsafe static UnsafeHelper() + static UnsafeHelper() { RuntimeHelpersType = typeof(RuntimeHelpers); AllocateUninitializedClone = (Func?)RuntimeHelpersType.GetMethod("AllocateUninitializedClone", BindingFlags.Static | BindingFlags.NonPublic)?.CreateDelegate(typeof(Func)); @@ -48,7 +48,7 @@ unsafe static UnsafeHelper() /// /// address [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe IntPtr GetPointer(ref T val) => (IntPtr)System.Runtime.CompilerServices.Unsafe.AsPointer(ref val); + public static IntPtr GetPointer(ref T val) => (IntPtr)System.Runtime.CompilerServices.Unsafe.AsPointer(ref val); //{ // fixed(void* p = &val) // { @@ -62,7 +62,7 @@ unsafe static UnsafeHelper() /// /// address [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void* GetPointer(object obj) => IL.GetPointer(obj); + public static void* GetPointer(object obj) => IL.GetPointer(obj); /// /// 获取对象实例的地址(Handle的位置) @@ -78,7 +78,7 @@ unsafe static UnsafeHelper() /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe IntPtr GetObjectRawDataAddress(object obj) + public static IntPtr GetObjectRawDataAddress(object obj) { return GetPointerIntPtr(obj) + IntPtr.Size; } @@ -88,7 +88,7 @@ public static unsafe IntPtr GetObjectRawDataAddress(object obj) /// /// /// - public static unsafe Span GetObjectRawDataAsSpan(object obj) where T : unmanaged + public static Span GetObjectRawDataAsSpan(object obj) where T : unmanaged { IntPtr first = GetObjectRawDataAddress(obj); ulong size = (ulong)GetObjectRawDataSize(obj) / (ulong)sizeof(T); @@ -100,14 +100,14 @@ public static unsafe Span GetObjectRawDataAsSpan(object obj) where T : unm /// /// /// - public static unsafe long GetObjectRawDataSize(T obj) where T : class + public static long GetObjectRawDataSize(T obj) where T : class { if (obj == null) return -1; IntPtr objptr = GetPointerIntPtr(obj); IntPtr rawDataP = objptr + sizeof(IntPtr); IntPtr objTable = *(IntPtr*)objptr; long size = (*(uint*)(objTable + 4)) - (2 * sizeof(nint)); - if((*(uint*)objTable & 2147483648U) > 0) + if ((*(uint*)objTable & 2147483648U) > 0) { size += ((long)(*(ushort*)objTable) * (*(uint*)rawDataP)); } @@ -120,7 +120,7 @@ public static unsafe long GetObjectRawDataSize(T obj) where T : class /// 获取对象原始数据大小, 如果获取失败返回-1 /// /// - public static unsafe long GetObjectRawDataSize() where T : class + public static long GetObjectRawDataSize() where T : class { IntPtr methodTable = typeof(T).TypeHandle.Value; long size = (*(uint*)(methodTable + 4)) - (2 * sizeof(nint)); @@ -147,7 +147,7 @@ public static unsafe long GetObjectRawDataSize() where T : class /// /// /// - public static unsafe T? Clone(this T obj) where T : class + public static T? Clone(this T obj) where T : class { if (obj == null) throw new ArgumentNullException(nameof(obj)); T? newObj = CloneEmptyObject(obj); //克隆对象 @@ -179,7 +179,7 @@ public static unsafe long GetObjectRawDataSize() where T : class /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe string ToAddress(this UIntPtr p) + public static string ToAddress(this UIntPtr p) { return "0x" + ((ulong)p).ToString("X").PadLeft(sizeof(UIntPtr) * 2, '0'); } @@ -190,7 +190,7 @@ public static unsafe string ToAddress(this UIntPtr p) /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe string ToAddress(this IntPtr p) + public static string ToAddress(this IntPtr p) { return "0x" + p.ToString("X").PadLeft(sizeof(IntPtr) * 2, '0'); } @@ -201,7 +201,7 @@ public static unsafe string ToAddress(this IntPtr p) /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe object ChangeObjectHandle(object obj, Type type) + public static object ChangeObjectHandle(object obj, Type type) { *(IntPtr*)GetPointer(obj) = type.TypeHandle.Value; return obj; @@ -212,7 +212,7 @@ public static unsafe object ChangeObjectHandle(object obj, Type type) /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe T ChangeObjectHandle(object obj) + public static T ChangeObjectHandle(object obj) { *(IntPtr*)GetPointer(obj) = typeof(T).TypeHandle.Value; return (T)obj; @@ -224,7 +224,7 @@ public static unsafe T ChangeObjectHandle(object obj) /// /// /// - public static unsafe object AllocObject(Type type, IntPtr size) + public static object AllocObject(Type type, IntPtr size) { #if NET6_0_OR_GREATER var p = (IntPtr)NativeMemory.AllocZeroed(((UIntPtr)(ulong)size + sizeof(IntPtr))); @@ -245,7 +245,7 @@ public static unsafe object AllocObject(Type type, IntPtr size) /// /// /// - public static unsafe T AllocObject(IntPtr size) where T : class + public static T AllocObject(IntPtr size) where T : class { #if NET6_0_OR_GREATER var p = (IntPtr)NativeMemory.AllocZeroed(((UIntPtr)(ulong)size + sizeof(IntPtr))); @@ -262,7 +262,7 @@ public static unsafe T AllocObject(IntPtr size) where T : class } //内存清0 - private static unsafe void Zero(void* p, IntPtr size) + private static void Zero(void* p, IntPtr size) { long size_long = (long)size; if (size_long > int.MaxValue) @@ -287,7 +287,7 @@ private static unsafe void Zero(void* p, IntPtr size) /// 申请一个对象,通过FreeObject释放 /// /// - public static unsafe T AllocObject() where T : class + public static T AllocObject() where T : class { var raw = GetObjectRawDataSize(); if (raw < 0) raw = 0; @@ -310,7 +310,7 @@ public static unsafe T AllocObject() where T : class /// 释放AllocObject创建的对象 /// /// - public static unsafe void FreeObject(object obj) + public static void FreeObject(object obj) { #if NET6_0_OR_GREATER NativeMemory.Free(GetPointer(obj)); @@ -324,9 +324,9 @@ public static unsafe void FreeObject(object obj) /// /// 字符串 /// - public static unsafe Span AsSpan(string str) + public static Span AsSpan(string str) { - fixed(char* p = str) + fixed (char* p = str) { return new Span(p, str.Length); } @@ -339,7 +339,7 @@ public static unsafe Span AsSpan(string str) /// /// /// - public static unsafe bool CompareRaw(object obj1, object obj2) + public static bool CompareRaw(object obj1, object obj2) { long obj1size = UnsafeHelper.GetObjectRawDataSize(obj1); long obj2size = UnsafeHelper.GetObjectRawDataSize(obj2); @@ -382,7 +382,7 @@ public static unsafe bool CompareRaw(object obj1, object obj2) /// 数组元素类型 /// 多维数组 /// - public static unsafe Span AsSpan(this Array array/*, int rank*/) + public static Span AsSpan(this Array array/*, int rank*/) { int rank = array.Rank; if (array == null) throw new ArgumentNullException(nameof(array)); @@ -399,9 +399,9 @@ public static unsafe Span AsSpan(this Array array/*, int rank*/) /// 父类/基类 /// 子类/派生类 /// - public static unsafe void CopyParentToChild(TParent parentObj, TChild childObj) - where TParent : class - where TChild : class , TParent + public static void CopyParentToChild(TParent parentObj, TChild childObj) + where TParent : class + where TChild : class, TParent { if (parentObj == null) throw new ArgumentNullException(nameof(parentObj)); if (childObj == null) throw new ArgumentNullException(nameof(childObj)); @@ -420,7 +420,7 @@ public static unsafe void CopyParentToChild(TParent parentObj, /// 父类/基类 /// 子类/派生类 /// - public static unsafe void CopyChildToParent(TChild childObj, TParent parentObj) + public static void CopyChildToParent(TChild childObj, TParent parentObj) where TParent : class where TChild : class, TParent { @@ -440,7 +440,7 @@ public static unsafe void CopyChildToParent(TChild childObj, TP /// /// /// - public static unsafe int GetArrayItemSize(Array array) + public static int GetArrayItemSize(Array array) { return *(ushort*)array.GetType().TypeHandle.Value; } @@ -452,7 +452,7 @@ public static unsafe int GetArrayItemSize(Array array) /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe T* ToPointer(this T[] str) // where T : unmanaged + public static T* ToPointer(this T[] str) // where T : unmanaged { return (T*)(GetPointerIntPtr(str) + sizeof(IntPtr) * 2).ToPointer(); } @@ -471,7 +471,7 @@ public static unsafe int GetArrayItemSize(Array array) /// /// /// - public static unsafe int GetFieldOffset(Type type, string fieldName) + public static int GetFieldOffset(Type type, string fieldName) { if (m_fieldHandle_offset == -1) return -1; var fieldInfo = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); @@ -488,7 +488,7 @@ public static unsafe int GetFieldOffset(Type type, string fieldName) /// /// /// - public static unsafe IntPtr GetFieldAddress(T obj, string fieldName) where T : class + public static IntPtr GetFieldAddress(T obj, string fieldName) where T : class { if (obj == null) return IntPtr.Zero; int offset = GetFieldOffset(obj.GetType(), fieldName); @@ -496,7 +496,7 @@ public static unsafe IntPtr GetFieldAddress(T obj, string fieldName) where T return GetObjectRawDataAddress(obj) + offset; } - private static unsafe bool SetFieldValue(IntPtr addr, TValue value) + private static bool SetFieldValue(IntPtr addr, TValue value) { if (addr == IntPtr.Zero) return false; if (value is ValueType) @@ -530,7 +530,7 @@ private static unsafe bool SetFieldValue(IntPtr addr, TValue value) /// /// /// - public static unsafe bool SetObjectFieldValue(T obj, string fieldName, TValue value) where T : class + public static bool SetObjectFieldValue(T obj, string fieldName, TValue value) where T : class { IntPtr addr = GetFieldAddress(obj, fieldName); if (addr == IntPtr.Zero) return false; @@ -546,7 +546,7 @@ public static unsafe bool SetObjectFieldValue(T obj, string fieldName /// /// /// - public static unsafe bool SetStructFieldValue(ref T obj, string fieldName, TValue value) where T : struct + public static bool SetStructFieldValue(ref T obj, string fieldName, TValue value) where T : struct { int offset = GetFieldOffset(typeof(T), fieldName); if (offset == -1) return false; From d0253e4f8fa6ae4fa2504e4a22e70ddcb22d7cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E4=BB=99=E5=A5=B3?= Date: Sat, 31 Dec 2022 18:53:48 +0800 Subject: [PATCH 2/3] updateupdateupdate --- UnsafeHelper.IL/IL.il | 7 +++++ UnsafeHelper/ManagedObject.cs | 44 ++++++++++++++++++++++++++++++++ UnsafeHelper/StructExtension.cs | 34 ++++++++++++++++++++++++ UnsafeHelper/UnsafeHelper.cs | 27 ++++++++------------ UnsafeHelper/UnsafeHelper.csproj | 1 + 5 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 UnsafeHelper/ManagedObject.cs create mode 100644 UnsafeHelper/StructExtension.cs diff --git a/UnsafeHelper.IL/IL.il b/UnsafeHelper.IL/IL.il index 9a81ac8..29269d4 100644 --- a/UnsafeHelper.IL/IL.il +++ b/UnsafeHelper.IL/IL.il @@ -30,4 +30,11 @@ ldarg.0 ret } + + .method public hidebysig static !!T As(void* objectAddress) cil managed aggressiveinlining + { + .maxstack 2 + ldarg.0 + ret + } } \ No newline at end of file diff --git a/UnsafeHelper/ManagedObject.cs b/UnsafeHelper/ManagedObject.cs new file mode 100644 index 0000000..3af20eb --- /dev/null +++ b/UnsafeHelper/ManagedObject.cs @@ -0,0 +1,44 @@ +using IlyfairyLib.Unsafe.Internal; +using System; +using System.Runtime.InteropServices; + +namespace IlyfairyLib.Unsafe; + +/// +/// 自动回收的托管对象 +/// +/// +public unsafe class ManagedObject where T : class +{ + /// + /// 前(nint)字节为TypeHandle + /// + private readonly byte[] data; + public int Size => data.Length; + public nint* Handle => (nint*)(UnsafeHelper.GetObjectRawDataAddress(data) + 8); + public T Object { get; private set; } + private readonly GCHandle gcHandle; + private ManagedObject(byte[] data, object obj) + { + Object = System.Runtime.CompilerServices.Unsafe.As(obj); + this.data = data; + } + public ManagedObject(int size) + { + if (size <= 8) size = 8; + size += 8; + data = new byte[size]; + var handle = Handle; + *handle = typeof(T).TypeHandle.Value; + Object = IL.As(handle); + gcHandle = GCHandle.Alloc(Object); + } + ~ManagedObject() + { + gcHandle.Free(); + } + public Span GetDataSpan() where T : unmanaged => new((byte*)Handle + sizeof(nint), Size / sizeof(T)); + public void ChangeType(Type type) => *Handle = type.TypeHandle.Value; + public void ChangeType() => *Handle = typeof(T).TypeHandle.Value; + public ManagedObject As() where TTo : class => System.Runtime.CompilerServices.Unsafe.As>(this); +} diff --git a/UnsafeHelper/StructExtension.cs b/UnsafeHelper/StructExtension.cs new file mode 100644 index 0000000..1bb6115 --- /dev/null +++ b/UnsafeHelper/StructExtension.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IlyfairyLib.Unsafe; + +public static class StructExtension +{ + public static unsafe TStruct ToStruct(this byte[] bytes) where TStruct : struct + { + if (sizeof(TStruct) != bytes.Length) + throw new ArgumentOutOfRangeException(nameof(bytes), "Bytes array should be the same length as struct size."); + TStruct val; + fixed (byte* p = bytes) + { + Buffer.MemoryCopy(p, &val, (ulong)sizeof(TStruct), (ulong)sizeof(TStruct)); + return val; + } + } + + public static unsafe TStruct ToStruct(this Span bytes) where TStruct : struct + { + if (sizeof(TStruct) != bytes.Length) + throw new ArgumentOutOfRangeException(nameof(bytes), "Bytes array should be the same length as struct size."); + TStruct val; + fixed (byte* p = bytes) + { + Buffer.MemoryCopy(p, &val, (ulong)sizeof(TStruct), (ulong)sizeof(TStruct)); + return val; + } + } +} diff --git a/UnsafeHelper/UnsafeHelper.cs b/UnsafeHelper/UnsafeHelper.cs index 44b5a44..ac88c6d 100644 --- a/UnsafeHelper/UnsafeHelper.cs +++ b/UnsafeHelper/UnsafeHelper.cs @@ -261,25 +261,20 @@ public static T AllocObject(IntPtr size) where T : class return obj; } - //内存清0 - private static void Zero(void* p, IntPtr size) + /// + /// 内存清0 + /// + /// + /// + public static void Zero(void* p, IntPtr size) { - long size_long = (long)size; - if (size_long > int.MaxValue) - { - int chunk = (int)((long)size / int.MaxValue); - int m = (int)((long)size % int.MaxValue); - long i = 0; - for (; i < chunk; i++) - { - new Span((void*)((long)p + i * int.MaxValue), int.MaxValue).Clear(); - } - new Span((void*)((long)p + i * int.MaxValue), m).Clear(); - } - else + while (size > (nint)int.MaxValue) { - new Span(p, (int)size_long).Clear(); + new Span(p, int.MaxValue).Clear(); + size -= int.MaxValue; + p = (byte*)p + int.MaxValue; } + new Span(p, (int)size).Clear(); } diff --git a/UnsafeHelper/UnsafeHelper.csproj b/UnsafeHelper/UnsafeHelper.csproj index 4443c4d..a265329 100644 --- a/UnsafeHelper/UnsafeHelper.csproj +++ b/UnsafeHelper/UnsafeHelper.csproj @@ -10,6 +10,7 @@ net5.0;net6.0 enable True + preview From 7d87eed57f5a5a5ffbd0528b0f89ac1bbc2e5a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E4=BB=99=E5=A5=B3?= Date: Sat, 31 Dec 2022 19:52:33 +0800 Subject: [PATCH 3/3] v2.3.0 --- UnsafeHelper/UnsafeHelper.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UnsafeHelper/UnsafeHelper.csproj b/UnsafeHelper/UnsafeHelper.csproj index a265329..a77bd9c 100644 --- a/UnsafeHelper/UnsafeHelper.csproj +++ b/UnsafeHelper/UnsafeHelper.csproj @@ -3,7 +3,7 @@ True UnsafeHelper - 2.2.1 + 2.3.0 ilyfairy C#不安全方法 true