// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//
// Note: These routines assume that the processor supports
// 32-bit aligned accesses. Migration to non-x86 platforms will
// need to examine and tune the implementations accordingly.
//
#define USE_EXTERNAL_MEMORY_OPERATIONS
namespace System {
using System;
using System.Runtime.CompilerServices;
//|
[NoCCtor]
[CLSCompliant(false)]
public sealed class Buffer
{
private Buffer() {
}
// This is a replacement for the memmove intrinsic.
// It performs better than the CRT one and the inline version
// originally from Lightning\Src\VM\COMSystem.cpp
[NoHeapAllocation]
public static unsafe void MoveMemory(byte* dmem, byte* smem, UIntPtr size)
{
MoveMemory(dmem, smem, (int)size);
}
#if USE_EXTERNAL_MEMORY_OPERATIONS
[AccessedByRuntime("output to header: defined in c++")]
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(64)]
[NoHeapAllocation]
public static unsafe extern void MoveMemory(byte* dmem, byte* smem, int size);
#else // !USE_EXTERNAL_MEMORY_OPERATIONS
[NoHeapAllocation]
public static unsafe void MoveMemory(byte* dmem, byte* smem, int size)
{
if (dmem <= smem) {
// make sure the destination is dword aligned
while ((((int)dmem ) & 0x3) != 0 && size >= 3) {
*dmem++ = *smem++;
size -= 1;
}
// copy 16 bytes at a time
if (size >= 16) {
size -= 16;
do {
((int *)dmem)[0] = ((int *)smem)[0];
((int *)dmem)[1] = ((int *)smem)[1];
((int *)dmem)[2] = ((int *)smem)[2];
((int *)dmem)[3] = ((int *)smem)[3];
dmem += 16;
smem += 16;
}
while ((size -= 16) >= 0);
}
// still 8 bytes or more left to copy?
if ((size & 8) != 0) {
((int *)dmem)[0] = ((int *)smem)[0];
((int *)dmem)[1] = ((int *)smem)[1];
dmem += 8;
smem += 8;
}
// still 4 bytes or more left to copy?
if ((size & 4) != 0) {
((int *)dmem)[0] = ((int *)smem)[0];
dmem += 4;
smem += 4;
}
// still 2 bytes or more left to copy?
if ((size & 2) != 0) {
((short *)dmem)[0] = ((short *)smem)[0];
dmem += 2;
smem += 2;
}
// still 1 byte left to copy?
if ((size & 1) != 0) {
dmem[0] = smem[0];
dmem += 1;
smem += 1;
}
} else {
smem += size;
dmem += size;
// make sure the destination is dword aligned
while ((((int)dmem) & 0x3) != 0 && size >= 3) {
*--dmem = *--smem;
size -= 1;
}
// copy 16 bytes at a time
if (size >= 16) {
size -= 16;
do {
dmem -= 16;
smem -= 16;
((int *)dmem)[3] = ((int *)smem)[3];
((int *)dmem)[2] = ((int *)smem)[2];
((int *)dmem)[1] = ((int *)smem)[1];
((int *)dmem)[0] = ((int *)smem)[0];
}
while ((size -= 16) >= 0);
}
// still 8 bytes or more left to copy?
if ((size & 8) != 0) {
dmem -= 8;
smem -= 8;
((int *)dmem)[1] = ((int *)smem)[1];
((int *)dmem)[0] = ((int *)smem)[0];
}
// still 4 bytes or more left to copy?
if ((size & 4) != 0) {
dmem -= 4;
smem -= 4;
((int *)dmem)[0] = ((int *)smem)[0];
}
// still 2 bytes or more left to copy?
if ((size & 2) != 0) {
dmem -= 2;
smem -= 2;
((short *)dmem)[0] = ((short *)smem)[0];
}
// still 1 byte left to copy?
if ((size & 1) != 0) {
dmem -= 1;
smem -= 1;
dmem[0] = smem[0];
}
}
}
#endif // !USE_EXTERNAL_MEMORY_OPERATIONS
// Copies from one primitive array to another primitive array without
// respecting types. This calls memmove internally.
//|
public static void BlockCopy(Array src, int srcOffset,
Array dst, int dstOffset, int count) {
if (src == null) {
throw new ArgumentNullException("src");
}
if (dst == null) {
throw new ArgumentNullException("dst");
}
InternalBlockCopy(src, srcOffset, dst, dstOffset, count);
}
// A very simple and efficient array copy that assumes all of the
// parameter validation has already been done. All counts here are
// in bytes.
internal static unsafe void InternalBlockCopy(Array src, int srcOffset,
Array dst, int dstOffset,
int count) {
VTable.Assert(src != null);
VTable.Assert(dst != null);
// Unfortunately, we must do a check to make sure we're writing
// within the bounds of the array. This will ensure that we don't
// overwrite memory elsewhere in the system nor do we write out junk.
// This can happen if multiple threads screw with our IO classes
// simultaneously without being threadsafe. Throw here. -- Brian
// Grunkemeyer, 5/9/2001
int srcLen = src.Length * src.vtable.arrayElementSize;
if (srcOffset < 0 || dstOffset < 0 || count < 0 ||
srcOffset > srcLen - count)
throw new IndexOutOfRangeException
("IndexOutOfRange_IORaceCondition");
if (src == dst) {
if (dstOffset > srcLen - count)
throw new IndexOutOfRangeException
("IndexOutOfRange_IORaceCondition");
} else {
int dstLen = dst.Length * dst.vtable.arrayElementSize;
if (dstOffset > dstLen - count)
throw new IndexOutOfRangeException
("IndexOutOfRange_IORaceCondition");
}
// Copy the data.
// Call our faster version of memmove, not the CRT one.
fixed (int *srcFieldPtr = &src.field1) {
fixed (int *dstFieldPtr = &dst.field1) {
byte *srcPtr = (byte *)
src.GetFirstElementAddress(srcFieldPtr);
byte *dstPtr = (byte *)
dst.GetFirstElementAddress(dstFieldPtr);
MoveMemory(dstPtr + dstOffset, srcPtr + srcOffset, count);
}
}
}
[NoHeapAllocation]
internal static unsafe void ZeroMemory(byte* dst, UIntPtr len)
{
ZeroMemory(dst, (int)len);
}
#if USE_EXTERNAL_MEMORY_OPERATIONS
[AccessedByRuntime("output to header: defined in c++")]
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(64)]
[NoHeapAllocation]
public static unsafe extern void ZeroMemory(byte* dst, int len);
#else // !USE_EXTERNAL_MEMORY_OPERATIONS
[NoHeapAllocation]
public static unsafe void ZeroMemory(byte* dst, int len)
{
// This is based on Peter Sollich's faster memcpy implementation,
// from COMString.cpp.
while ( (((int)dst) & 0x03) != 0 && len >= 3 ) {
*dst = 0;
len -= 1;
}
if (len >= 16) {
len -= 16;
do {
((int*)dst)[0] = 0;
((int*)dst)[1] = 0;
((int*)dst)[2] = 0;
((int*)dst)[3] = 0;
dst += 16;
} while ((len -= 16) >= 0);
}
if ((len & 8) > 0) {
((int*)dst)[0] = 0;
((int*)dst)[1] = 0;
dst += 8;
}
if ((len & 4) > 0) {
((int*)dst)[0] = 0;
dst += 4;
}
if ((len & 2) != 0) {
((short*)dst)[0] = 0;
dst += 2;
}
if ((len & 1) != 0)
*dst++ = 0;
}
#endif // !USE_EXTERNAL_MEMORY_OPERATIONS
[AccessedByRuntime("output to header: defined in asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(32)]
[NoHeapAllocation]
internal static unsafe extern void ZeroPages(byte* dst, int len);
[AccessedByRuntime("output to header: defined in asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(32)]
[NoHeapAllocation]
internal static unsafe extern void CopyPages(byte* dst, byte *src, int len);
// 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.
//
//|
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
public static extern byte GetByte(Array array, int index);
// 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.
//
//|
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
public static extern void SetByte(Array array, int index, byte value);
// 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).
//
//|
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
public static extern int ByteLength(Array array);
}
}