Xamarin Public Jenkins (auto-signing) e79aa3c0ed Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
2016-08-03 10:59:49 +00:00

569 lines
21 KiB
C#

// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
namespace System {
//Only contains static methods. Does not require serialization
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
using System.Security;
using System.Runtime;
[System.Runtime.InteropServices.ComVisible(true)]
public static partial class Buffer
{
#if !MONO
// Copies from one primitive array to another primitive array without
// respecting types. This calls memmove internally. The count and
// offset parameters here are in bytes. If you want to use traditional
// array element indices and counts, use Array.Copy.
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern void BlockCopy(Array src, int srcOffset,
Array dst, int dstOffset, int count);
#endif
// A very simple and efficient memmove that assumes all of the
// parameter validation has already been done. The count and offset
// parameters here are in bytes. If you want to use traditional
// array element indices and counts, use Array.Copy.
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern bool InternalBlockCopy(Array src, int srcOffsetBytes,
Array dst, int dstOffsetBytes, int byteCount);
// This is ported from the optimized CRT assembly in memchr.asm. The JIT generates
// pretty good code here and this ends up being within a couple % of the CRT asm.
// It is however cross platform as the CRT hasn't ported their fast version to 64-bit
// platforms.
//
[System.Security.SecurityCritical] // auto-generated
internal unsafe static int IndexOfByte(byte* src, byte value, int index, int count)
{
Contract.Assert(src != null, "src should not be null");
byte* pByte = src + index;
// Align up the pointer to sizeof(int).
while (((int)pByte & 3) != 0)
{
if (count == 0)
return -1;
else if (*pByte == value)
return (int) (pByte - src);
count--;
pByte++;
}
// Fill comparer with value byte for comparisons
//
// comparer = 0/0/value/value
uint comparer = (((uint)value << 8) + (uint)value);
// comparer = value/value/value/value
comparer = (comparer << 16) + comparer;
// Run through buffer until we hit a 4-byte section which contains
// the byte we're looking for or until we exhaust the buffer.
while (count > 3)
{
// Test the buffer for presence of value. comparer contains the byte
// replicated 4 times.
uint t1 = *(uint*)pByte;
t1 = t1 ^ comparer;
uint t2 = 0x7efefeff + t1;
t1 = t1 ^ 0xffffffff;
t1 = t1 ^ t2;
t1 = t1 & 0x81010100;
// if t1 is zero then these 4-bytes don't contain a match
if (t1 != 0)
{
// We've found a match for value, figure out which position it's in.
int foundIndex = (int) (pByte - src);
if (pByte[0] == value)
return foundIndex;
else if (pByte[1] == value)
return foundIndex + 1;
else if (pByte[2] == value)
return foundIndex + 2;
else if (pByte[3] == value)
return foundIndex + 3;
}
count -= 4;
pByte += 4;
}
// Catch any bytes that might be left at the tail of the buffer
while (count > 0)
{
if (*pByte == value)
return (int) (pByte - src);
count--;
pByte++;
}
// If we don't have a match return -1;
return -1;
}
#if !MONO
// Returns a bool to indicate if the array is of primitive data types
// or not.
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern bool IsPrimitiveTypeArray(Array array);
#endif
// Gets a particular byte out of the array. The array must be an
// array of primitives.
//
// This essentially does the following:
// return ((byte*)array) + index.
//
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern byte _GetByte(Array array, int index);
#if !MONO
[System.Security.SecuritySafeCritical] // auto-generated
public static byte GetByte(Array array, int index)
{
// Is the array present?
if (array == null)
throw new ArgumentNullException("array");
// Is it of primitive types?
if (!IsPrimitiveTypeArray(array))
throw new ArgumentException(Environment.GetResourceString("Arg_MustBePrimArray"), "array");
// Is the index in valid range of the array?
if (index < 0 || index >= _ByteLength(array))
throw new ArgumentOutOfRangeException("index");
return _GetByte(array, index);
}
#endif
// Sets a particular byte in an the array. The array must be an
// array of primitives.
//
// This essentially does the following:
// *(((byte*)array) + index) = value.
//
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern void _SetByte(Array array, int index, byte value);
#if !MONO
[System.Security.SecuritySafeCritical] // auto-generated
public static void SetByte(Array array, int index, byte value)
{
// Is the array present?
if (array == null)
throw new ArgumentNullException("array");
// Is it of primitive types?
if (!IsPrimitiveTypeArray(array))
throw new ArgumentException(Environment.GetResourceString("Arg_MustBePrimArray"), "array");
// Is the index in valid range of the array?
if (index < 0 || index >= _ByteLength(array))
throw new ArgumentOutOfRangeException("index");
// Make the FCall to do the work
_SetByte(array, index, value);
}
#endif
// Gets a particular byte out of the array. The array must be an
// array of primitives.
//
// This essentially does the following:
// return array.length * sizeof(array.UnderlyingElementType).
//
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern int _ByteLength(Array array);
#if !MONO
[System.Security.SecuritySafeCritical] // auto-generated
public static int ByteLength(Array array)
{
// Is the array present?
if (array == null)
throw new ArgumentNullException("array");
// Is it of primitive types?
if (!IsPrimitiveTypeArray(array))
throw new ArgumentException(Environment.GetResourceString("Arg_MustBePrimArray"), "array");
return _ByteLength(array);
}
#endif
[System.Security.SecurityCritical] // auto-generated
internal unsafe static void ZeroMemory(byte* src, long len)
{
while(len-- > 0)
*(src + len) = 0;
}
[System.Security.SecurityCritical] // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal unsafe static void Memcpy(byte[] dest, int destIndex, byte* src, int srcIndex, int len) {
Contract.Assert( (srcIndex >= 0) && (destIndex >= 0) && (len >= 0), "Index and length must be non-negative!");
Contract.Assert(dest.Length - destIndex >= len, "not enough bytes in dest");
// If dest has 0 elements, the fixed statement will throw an
// IndexOutOfRangeException. Special-case 0-byte copies.
if (len==0)
return;
fixed(byte* pDest = dest) {
Memcpy(pDest + destIndex, src + srcIndex, len);
}
}
[SecurityCritical]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal unsafe static void Memcpy(byte* pDest, int destIndex, byte[] src, int srcIndex, int len)
{
Contract.Assert( (srcIndex >= 0) && (destIndex >= 0) && (len >= 0), "Index and length must be non-negative!");
Contract.Assert(src.Length - srcIndex >= len, "not enough bytes in src");
// If dest has 0 elements, the fixed statement will throw an
// IndexOutOfRangeException. Special-case 0-byte copies.
if (len==0)
return;
fixed(byte* pSrc = src) {
Memcpy(pDest + destIndex, pSrc + srcIndex, len);
}
}
#if !MONO
// This is tricky to get right AND fast, so lets make it useful for the whole Fx.
// E.g. System.Runtime.WindowsRuntime!WindowsRuntimeBufferExtensions.MemCopy uses it.
// This method has a slightly different behavior on arm and other platforms.
// On arm this method behaves like memcpy and does not handle overlapping buffers.
// While on other platforms it behaves like memmove and handles overlapping buffers.
// This behavioral difference is unfortunate but intentional because
// 1. This method is given access to other internal dlls and this close to release we do not want to change it.
// 2. It is difficult to get this right for arm and again due to release dates we would like to visit it later.
[FriendAccessAllowed]
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.None)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
#if ARM
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal unsafe static extern void Memcpy(byte* dest, byte* src, int len);
#else // ARM
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
internal unsafe static void Memcpy(byte* dest, byte* src, int len) {
Contract.Assert(len >= 0, "Negative length in memcopy!");
Memmove(dest, src, (uint)len);
}
#endif // ARM
// This method has different signature for x64 and other platforms and is done for performance reasons.
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.None)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
#if WIN64
internal unsafe static void Memmove(byte* dest, byte* src, ulong len)
#else
internal unsafe static void Memmove(byte* dest, byte* src, uint len)
#endif
{
// P/Invoke into the native version when the buffers are overlapping and the copy needs to be performed backwards
// This check can produce false positives for lengths greater than Int32.MaxInt. It is fine because we want to use PInvoke path for the large lengths anyway.
#if WIN64
if ((ulong)dest - (ulong)src < len) goto PInvoke;
#else
if (((uint)dest - (uint)src) < len) goto PInvoke;
#endif
//
// This is portable version of memcpy. It mirrors what the hand optimized assembly versions of memcpy typically do.
//
// Ideally, we would just use the cpblk IL instruction here. Unfortunately, cpblk IL instruction is not as efficient as
// possible yet and so we have this implementation here for now.
//
switch (len)
{
case 0:
return;
case 1:
*dest = *src;
return;
case 2:
*(short *)dest = *(short *)src;
return;
case 3:
*(short *)dest = *(short *)src;
*(dest + 2) = *(src + 2);
return;
case 4:
*(int *)dest = *(int *)src;
return;
case 5:
*(int*)dest = *(int*)src;
*(dest + 4) = *(src + 4);
return;
case 6:
*(int*)dest = *(int*)src;
*(short*)(dest + 4) = *(short*)(src + 4);
return;
case 7:
*(int*)dest = *(int*)src;
*(short*)(dest + 4) = *(short*)(src + 4);
*(dest + 6) = *(src + 6);
return;
case 8:
#if WIN64
*(long*)dest = *(long*)src;
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
#endif
return;
case 9:
#if WIN64
*(long*)dest = *(long*)src;
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
#endif
*(dest + 8) = *(src + 8);
return;
case 10:
#if WIN64
*(long*)dest = *(long*)src;
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
#endif
*(short*)(dest + 8) = *(short*)(src + 8);
return;
case 11:
#if WIN64
*(long*)dest = *(long*)src;
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
#endif
*(short*)(dest + 8) = *(short*)(src + 8);
*(dest + 10) = *(src + 10);
return;
case 12:
#if WIN64
*(long*)dest = *(long*)src;
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
#endif
*(int*)(dest + 8) = *(int*)(src + 8);
return;
case 13:
#if WIN64
*(long*)dest = *(long*)src;
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
#endif
*(int*)(dest + 8) = *(int*)(src + 8);
*(dest + 12) = *(src + 12);
return;
case 14:
#if WIN64
*(long*)dest = *(long*)src;
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
#endif
*(int*)(dest + 8) = *(int*)(src + 8);
*(short*)(dest + 12) = *(short*)(src + 12);
return;
case 15:
#if WIN64
*(long*)dest = *(long*)src;
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
#endif
*(int*)(dest + 8) = *(int*)(src + 8);
*(short*)(dest + 12) = *(short*)(src + 12);
*(dest + 14) = *(src + 14);
return;
case 16:
#if WIN64
*(long*)dest = *(long*)src;
*(long*)(dest + 8) = *(long*)(src + 8);
#else
*(int*)dest = *(int*)src;
*(int*)(dest + 4) = *(int*)(src + 4);
*(int*)(dest + 8) = *(int*)(src + 8);
*(int*)(dest + 12) = *(int*)(src + 12);
#endif
return;
default:
break;
}
// P/Invoke into the native version for large lengths
if (len >= 512) goto PInvoke;
if (((int)dest & 3) != 0)
{
if (((int)dest & 1) != 0)
{
*dest = *src;
src++;
dest++;
len--;
if (((int)dest & 2) == 0)
goto Aligned;
}
*(short *)dest = *(short *)src;
src += 2;
dest += 2;
len -= 2;
Aligned: ;
}
#if WIN64
if (((int)dest & 4) != 0)
{
*(int *)dest = *(int *)src;
src += 4;
dest += 4;
len -= 4;
}
#endif
#if WIN64
ulong count = len / 16;
#else
uint count = len / 16;
#endif
while (count > 0)
{
#if WIN64
((long*)dest)[0] = ((long*)src)[0];
((long*)dest)[1] = ((long*)src)[1];
#else
((int*)dest)[0] = ((int*)src)[0];
((int*)dest)[1] = ((int*)src)[1];
((int*)dest)[2] = ((int*)src)[2];
((int*)dest)[3] = ((int*)src)[3];
#endif
dest += 16;
src += 16;
count--;
}
if ((len & 8) != 0)
{
#if WIN64
((long*)dest)[0] = ((long*)src)[0];
#else
((int*)dest)[0] = ((int*)src)[0];
((int*)dest)[1] = ((int*)src)[1];
#endif
dest += 8;
src += 8;
}
if ((len & 4) != 0)
{
((int*)dest)[0] = ((int*)src)[0];
dest += 4;
src += 4;
}
if ((len & 2) != 0)
{
((short*)dest)[0] = ((short*)src)[0];
dest += 2;
src += 2;
}
if ((len & 1) != 0)
*dest = *src;
return;
PInvoke:
_Memmove(dest, src, len);
}
// Non-inlinable wrapper around the QCall that avoids poluting the fast path
// with P/Invoke prolog/epilog.
[SecurityCritical]
[ResourceExposure(ResourceScope.None)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[MethodImplAttribute(MethodImplOptions.NoInlining)]
#if WIN64
private unsafe static void _Memmove(byte* dest, byte* src, ulong len)
#else
private unsafe static void _Memmove(byte* dest, byte* src, uint len)
#endif
{
__Memmove(dest, src, len);
}
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
[SecurityCritical]
[ResourceExposure(ResourceScope.None)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
#if WIN64
extern private unsafe static void __Memmove(byte* dest, byte* src, ulong len);
#else
extern private unsafe static void __Memmove(byte* dest, byte* src, uint len);
#endif
// The attributes on this method are chosen for best JIT performance.
// Please do not edit unless intentional.
[System.Security.SecurityCritical]
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
public static unsafe void MemoryCopy(void* source, void* destination, long destinationSizeInBytes, long sourceBytesToCopy)
{
if (sourceBytesToCopy > destinationSizeInBytes)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.sourceBytesToCopy);
}
#if WIN64
Memmove((byte*)destination, (byte*)source, checked((ulong) sourceBytesToCopy));
#else
Memmove((byte*)destination, (byte*)source, checked((uint)sourceBytesToCopy));
#endif // WIN64
}
// The attributes on this method are chosen for best JIT performance.
// Please do not edit unless intentional.
[System.Security.SecurityCritical]
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
public static unsafe void MemoryCopy(void* source, void* destination, ulong destinationSizeInBytes, ulong sourceBytesToCopy)
{
if (sourceBytesToCopy > destinationSizeInBytes)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.sourceBytesToCopy);
}
#if WIN64
Memmove((byte*)destination, (byte*)source, sourceBytesToCopy);
#else
Memmove((byte*)destination, (byte*)source, checked((uint)sourceBytesToCopy));
#endif // WIN64
}
#endif
}
}