public static IntPtr Set(byte *dest, int c, long count) { Debug.Assert(count >= 0); return(PlatformDetails.RunningOnPosix ? Syscall.Set(dest, c, count) : Win32UnmanagedMemory.Set(dest, c, count)); }
public static int Move(byte *dest, byte *src, long count) { Debug.Assert(count >= 0); return(PlatformDetails.RunningOnPosix ? Syscall.Move(dest, src, count) : Win32UnmanagedMemory.Move(dest, src, count)); }
public static int Compare(byte *b1, byte *b2, long count) { Debug.Assert(count >= 0); return(PlatformDetails.RunningOnPosix ? Syscall.Compare(b1, b2, count) : Win32UnmanagedMemory.Compare(b1, b2, count)); }
public static void Move(byte *dest, byte *src, int n) { // if dest and src overlaps, we need to call specifically to memmove pinvoke supporting overlapping if (dest + n >= src && src + n >= dest) { var _ = PlatformDetails.RunningOnPosix ? Syscall.Move(dest, src, n) : Win32UnmanagedMemory.Move(dest, src, n); return; } Copy(dest, src, n); }
public static int CompareInline(void *p1, void *p2, int size) { // If we use an unmanaged bulk version with an inline compare the caller site does not get optimized properly. // If you know you will be comparing big memory chunks do not use the inline version. if (size > CompareInlineVsCallThreshold) { goto UnmanagedCompare; } byte *bpx = (byte *)p1; byte *bpy = (byte *)p2; // PERF: This allows us to do pointer arithmetics and use relative addressing using the // hardware instructions without needed an extra register. long offset = bpy - bpx; if ((size & 7) == 0) { goto ProcessAligned; } // We process first the "unaligned" size. ulong xor; if ((size & 4) != 0) { xor = *((uint *)bpx) ^ *((uint *)(bpx + offset)); if (xor != 0) { goto Tail; } bpx += 4; } if ((size & 2) != 0) { xor = (ulong)(*((ushort *)bpx) ^ *((ushort *)(bpx + offset))); if (xor != 0) { goto Tail; } bpx += 2; } if ((size & 1) != 0) { int value = *bpx - *(bpx + offset); if (value != 0) { return(value); } bpx += 1; } ProcessAligned: byte *end = (byte *)p1 + size; byte *loopEnd = end - 16; while (bpx <= loopEnd) { // PERF: JIT will emit: ```{op} {reg}, qword ptr [rdx+rax]``` if (*((ulong *)bpx) != *(ulong *)(bpx + offset)) { goto XorTail; } if (*((ulong *)(bpx + 8)) != *(ulong *)(bpx + 8 + offset)) { bpx += 8; goto XorTail; } bpx += 16; } if (bpx < end) { goto XorTail; } return(0); XorTail : xor = *((ulong *)bpx) ^ *(ulong *)(bpx + offset); Tail: // Fast-path for equals if (xor == 0) { return(0); } // PERF: This is a bit twiddling hack. Given that bitwise xoring 2 values flag the bits difference, // we can use that we know we are running on little endian hardware and the very first bit set // will correspond to the first byte which is different. bpx += Bits.TrailingZeroesInBytes(xor); return(*bpx - *(bpx + offset)); UnmanagedCompare: return(PlatformDetails.RunningOnPosix ? Syscall.Compare((byte *)p1, (byte *)p2, size) : Win32UnmanagedMemory.Compare((byte *)p1, (byte *)p2, size)); }
public static IntPtr Copy(byte *dest, byte *src, int count) { return(Platform.RunningOnPosix ? PosixUnmanagedMemory.Copy(dest, src, count) : Win32UnmanagedMemory.Copy(dest, src, count)); }
public static IntPtr Set(byte *dest, int c, int count) { return(Platform.RunningOnPosix ? PosixUnmanagedMemory.Set(dest, c, count) : Win32UnmanagedMemory.Set(dest, c, count)); }
public static int Move(byte *b1, byte *b2, int count) { return(Platform.RunningOnPosix ? PosixUnmanagedMemory.Move(b1, b2, count) : Win32UnmanagedMemory.Move(b1, b2, count)); }