PageRenderTime 46ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/referencesource/mscorlib/system/buffer.cs

https://github.com/pruiz/mono
C# | 568 lines | 436 code | 43 blank | 89 comment | 67 complexity | 69595ad55e470cd1ab59b5ecff382935 MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. // ==++==
  2. //
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. //
  5. // ==--==
  6. namespace System {
  7. //Only contains static methods. Does not require serialization
  8. using System;
  9. using System.Runtime.CompilerServices;
  10. using System.Runtime.ConstrainedExecution;
  11. using System.Runtime.InteropServices;
  12. using System.Runtime.Versioning;
  13. using System.Diagnostics.Contracts;
  14. using System.Security;
  15. using System.Runtime;
  16. [System.Runtime.InteropServices.ComVisible(true)]
  17. public static partial class Buffer
  18. {
  19. #if !MONO
  20. // Copies from one primitive array to another primitive array without
  21. // respecting types. This calls memmove internally. The count and
  22. // offset parameters here are in bytes. If you want to use traditional
  23. // array element indices and counts, use Array.Copy.
  24. [System.Security.SecuritySafeCritical] // auto-generated
  25. [ResourceExposure(ResourceScope.None)]
  26. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  27. public static extern void BlockCopy(Array src, int srcOffset,
  28. Array dst, int dstOffset, int count);
  29. #endif
  30. // A very simple and efficient memmove that assumes all of the
  31. // parameter validation has already been done. The count and offset
  32. // parameters here are in bytes. If you want to use traditional
  33. // array element indices and counts, use Array.Copy.
  34. [System.Security.SecuritySafeCritical] // auto-generated
  35. [ResourceExposure(ResourceScope.None)]
  36. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  37. internal static extern bool InternalBlockCopy(Array src, int srcOffsetBytes,
  38. Array dst, int dstOffsetBytes, int byteCount);
  39. // This is ported from the optimized CRT assembly in memchr.asm. The JIT generates
  40. // pretty good code here and this ends up being within a couple % of the CRT asm.
  41. // It is however cross platform as the CRT hasn't ported their fast version to 64-bit
  42. // platforms.
  43. //
  44. [System.Security.SecurityCritical] // auto-generated
  45. internal unsafe static int IndexOfByte(byte* src, byte value, int index, int count)
  46. {
  47. Contract.Assert(src != null, "src should not be null");
  48. byte* pByte = src + index;
  49. // Align up the pointer to sizeof(int).
  50. while (((int)pByte & 3) != 0)
  51. {
  52. if (count == 0)
  53. return -1;
  54. else if (*pByte == value)
  55. return (int) (pByte - src);
  56. count--;
  57. pByte++;
  58. }
  59. // Fill comparer with value byte for comparisons
  60. //
  61. // comparer = 0/0/value/value
  62. uint comparer = (((uint)value << 8) + (uint)value);
  63. // comparer = value/value/value/value
  64. comparer = (comparer << 16) + comparer;
  65. // Run through buffer until we hit a 4-byte section which contains
  66. // the byte we're looking for or until we exhaust the buffer.
  67. while (count > 3)
  68. {
  69. // Test the buffer for presence of value. comparer contains the byte
  70. // replicated 4 times.
  71. uint t1 = *(uint*)pByte;
  72. t1 = t1 ^ comparer;
  73. uint t2 = 0x7efefeff + t1;
  74. t1 = t1 ^ 0xffffffff;
  75. t1 = t1 ^ t2;
  76. t1 = t1 & 0x81010100;
  77. // if t1 is zero then these 4-bytes don't contain a match
  78. if (t1 != 0)
  79. {
  80. // We've found a match for value, figure out which position it's in.
  81. int foundIndex = (int) (pByte - src);
  82. if (pByte[0] == value)
  83. return foundIndex;
  84. else if (pByte[1] == value)
  85. return foundIndex + 1;
  86. else if (pByte[2] == value)
  87. return foundIndex + 2;
  88. else if (pByte[3] == value)
  89. return foundIndex + 3;
  90. }
  91. count -= 4;
  92. pByte += 4;
  93. }
  94. // Catch any bytes that might be left at the tail of the buffer
  95. while (count > 0)
  96. {
  97. if (*pByte == value)
  98. return (int) (pByte - src);
  99. count--;
  100. pByte++;
  101. }
  102. // If we don't have a match return -1;
  103. return -1;
  104. }
  105. #if !MONO
  106. // Returns a bool to indicate if the array is of primitive data types
  107. // or not.
  108. [System.Security.SecurityCritical] // auto-generated
  109. [ResourceExposure(ResourceScope.None)]
  110. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  111. private static extern bool IsPrimitiveTypeArray(Array array);
  112. #endif
  113. // Gets a particular byte out of the array. The array must be an
  114. // array of primitives.
  115. //
  116. // This essentially does the following:
  117. // return ((byte*)array) + index.
  118. //
  119. [System.Security.SecurityCritical] // auto-generated
  120. [ResourceExposure(ResourceScope.None)]
  121. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  122. private static extern byte _GetByte(Array array, int index);
  123. #if !MONO
  124. [System.Security.SecuritySafeCritical] // auto-generated
  125. public static byte GetByte(Array array, int index)
  126. {
  127. // Is the array present?
  128. if (array == null)
  129. throw new ArgumentNullException("array");
  130. // Is it of primitive types?
  131. if (!IsPrimitiveTypeArray(array))
  132. throw new ArgumentException(Environment.GetResourceString("Arg_MustBePrimArray"), "array");
  133. // Is the index in valid range of the array?
  134. if (index < 0 || index >= _ByteLength(array))
  135. throw new ArgumentOutOfRangeException("index");
  136. return _GetByte(array, index);
  137. }
  138. #endif
  139. // Sets a particular byte in an the array. The array must be an
  140. // array of primitives.
  141. //
  142. // This essentially does the following:
  143. // *(((byte*)array) + index) = value.
  144. //
  145. [System.Security.SecurityCritical] // auto-generated
  146. [ResourceExposure(ResourceScope.None)]
  147. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  148. private static extern void _SetByte(Array array, int index, byte value);
  149. #if !MONO
  150. [System.Security.SecuritySafeCritical] // auto-generated
  151. public static void SetByte(Array array, int index, byte value)
  152. {
  153. // Is the array present?
  154. if (array == null)
  155. throw new ArgumentNullException("array");
  156. // Is it of primitive types?
  157. if (!IsPrimitiveTypeArray(array))
  158. throw new ArgumentException(Environment.GetResourceString("Arg_MustBePrimArray"), "array");
  159. // Is the index in valid range of the array?
  160. if (index < 0 || index >= _ByteLength(array))
  161. throw new ArgumentOutOfRangeException("index");
  162. // Make the FCall to do the work
  163. _SetByte(array, index, value);
  164. }
  165. #endif
  166. // Gets a particular byte out of the array. The array must be an
  167. // array of primitives.
  168. //
  169. // This essentially does the following:
  170. // return array.length * sizeof(array.UnderlyingElementType).
  171. //
  172. [System.Security.SecurityCritical] // auto-generated
  173. [ResourceExposure(ResourceScope.None)]
  174. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  175. private static extern int _ByteLength(Array array);
  176. #if !MONO
  177. [System.Security.SecuritySafeCritical] // auto-generated
  178. public static int ByteLength(Array array)
  179. {
  180. // Is the array present?
  181. if (array == null)
  182. throw new ArgumentNullException("array");
  183. // Is it of primitive types?
  184. if (!IsPrimitiveTypeArray(array))
  185. throw new ArgumentException(Environment.GetResourceString("Arg_MustBePrimArray"), "array");
  186. return _ByteLength(array);
  187. }
  188. #endif
  189. [System.Security.SecurityCritical] // auto-generated
  190. internal unsafe static void ZeroMemory(byte* src, long len)
  191. {
  192. while(len-- > 0)
  193. *(src + len) = 0;
  194. }
  195. [System.Security.SecurityCritical] // auto-generated
  196. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  197. internal unsafe static void Memcpy(byte[] dest, int destIndex, byte* src, int srcIndex, int len) {
  198. Contract.Assert( (srcIndex >= 0) && (destIndex >= 0) && (len >= 0), "Index and length must be non-negative!");
  199. Contract.Assert(dest.Length - destIndex >= len, "not enough bytes in dest");
  200. // If dest has 0 elements, the fixed statement will throw an
  201. // IndexOutOfRangeException. Special-case 0-byte copies.
  202. if (len==0)
  203. return;
  204. fixed(byte* pDest = dest) {
  205. Memcpy(pDest + destIndex, src + srcIndex, len);
  206. }
  207. }
  208. [SecurityCritical]
  209. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  210. internal unsafe static void Memcpy(byte* pDest, int destIndex, byte[] src, int srcIndex, int len)
  211. {
  212. Contract.Assert( (srcIndex >= 0) && (destIndex >= 0) && (len >= 0), "Index and length must be non-negative!");
  213. Contract.Assert(src.Length - srcIndex >= len, "not enough bytes in src");
  214. // If dest has 0 elements, the fixed statement will throw an
  215. // IndexOutOfRangeException. Special-case 0-byte copies.
  216. if (len==0)
  217. return;
  218. fixed(byte* pSrc = src) {
  219. Memcpy(pDest + destIndex, pSrc + srcIndex, len);
  220. }
  221. }
  222. #if !MONO
  223. // This is tricky to get right AND fast, so lets make it useful for the whole Fx.
  224. // E.g. System.Runtime.WindowsRuntime!WindowsRuntimeBufferExtensions.MemCopy uses it.
  225. // This method has a slightly different behavior on arm and other platforms.
  226. // On arm this method behaves like memcpy and does not handle overlapping buffers.
  227. // While on other platforms it behaves like memmove and handles overlapping buffers.
  228. // This behavioral difference is unfortunate but intentional because
  229. // 1. This method is given access to other internal dlls and this close to release we do not want to change it.
  230. // 2. It is difficult to get this right for arm and again due to release dates we would like to visit it later.
  231. [FriendAccessAllowed]
  232. [System.Security.SecurityCritical]
  233. [ResourceExposure(ResourceScope.None)]
  234. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  235. #if ARM
  236. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  237. internal unsafe static extern void Memcpy(byte* dest, byte* src, int len);
  238. #else // ARM
  239. [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
  240. internal unsafe static void Memcpy(byte* dest, byte* src, int len) {
  241. Contract.Assert(len >= 0, "Negative length in memcopy!");
  242. Memmove(dest, src, (uint)len);
  243. }
  244. #endif // ARM
  245. // This method has different signature for x64 and other platforms and is done for performance reasons.
  246. [System.Security.SecurityCritical]
  247. [ResourceExposure(ResourceScope.None)]
  248. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  249. #if WIN64
  250. internal unsafe static void Memmove(byte* dest, byte* src, ulong len)
  251. #else
  252. internal unsafe static void Memmove(byte* dest, byte* src, uint len)
  253. #endif
  254. {
  255. // P/Invoke into the native version when the buffers are overlapping and the copy needs to be performed backwards
  256. // 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.
  257. #if WIN64
  258. if ((ulong)dest - (ulong)src < len) goto PInvoke;
  259. #else
  260. if (((uint)dest - (uint)src) < len) goto PInvoke;
  261. #endif
  262. //
  263. // This is portable version of memcpy. It mirrors what the hand optimized assembly versions of memcpy typically do.
  264. //
  265. // Ideally, we would just use the cpblk IL instruction here. Unfortunately, cpblk IL instruction is not as efficient as
  266. // possible yet and so we have this implementation here for now.
  267. //
  268. switch (len)
  269. {
  270. case 0:
  271. return;
  272. case 1:
  273. *dest = *src;
  274. return;
  275. case 2:
  276. *(short *)dest = *(short *)src;
  277. return;
  278. case 3:
  279. *(short *)dest = *(short *)src;
  280. *(dest + 2) = *(src + 2);
  281. return;
  282. case 4:
  283. *(int *)dest = *(int *)src;
  284. return;
  285. case 5:
  286. *(int*)dest = *(int*)src;
  287. *(dest + 4) = *(src + 4);
  288. return;
  289. case 6:
  290. *(int*)dest = *(int*)src;
  291. *(short*)(dest + 4) = *(short*)(src + 4);
  292. return;
  293. case 7:
  294. *(int*)dest = *(int*)src;
  295. *(short*)(dest + 4) = *(short*)(src + 4);
  296. *(dest + 6) = *(src + 6);
  297. return;
  298. case 8:
  299. #if WIN64
  300. *(long*)dest = *(long*)src;
  301. #else
  302. *(int*)dest = *(int*)src;
  303. *(int*)(dest + 4) = *(int*)(src + 4);
  304. #endif
  305. return;
  306. case 9:
  307. #if WIN64
  308. *(long*)dest = *(long*)src;
  309. #else
  310. *(int*)dest = *(int*)src;
  311. *(int*)(dest + 4) = *(int*)(src + 4);
  312. #endif
  313. *(dest + 8) = *(src + 8);
  314. return;
  315. case 10:
  316. #if WIN64
  317. *(long*)dest = *(long*)src;
  318. #else
  319. *(int*)dest = *(int*)src;
  320. *(int*)(dest + 4) = *(int*)(src + 4);
  321. #endif
  322. *(short*)(dest + 8) = *(short*)(src + 8);
  323. return;
  324. case 11:
  325. #if WIN64
  326. *(long*)dest = *(long*)src;
  327. #else
  328. *(int*)dest = *(int*)src;
  329. *(int*)(dest + 4) = *(int*)(src + 4);
  330. #endif
  331. *(short*)(dest + 8) = *(short*)(src + 8);
  332. *(dest + 10) = *(src + 10);
  333. return;
  334. case 12:
  335. #if WIN64
  336. *(long*)dest = *(long*)src;
  337. #else
  338. *(int*)dest = *(int*)src;
  339. *(int*)(dest + 4) = *(int*)(src + 4);
  340. #endif
  341. *(int*)(dest + 8) = *(int*)(src + 8);
  342. return;
  343. case 13:
  344. #if WIN64
  345. *(long*)dest = *(long*)src;
  346. #else
  347. *(int*)dest = *(int*)src;
  348. *(int*)(dest + 4) = *(int*)(src + 4);
  349. #endif
  350. *(int*)(dest + 8) = *(int*)(src + 8);
  351. *(dest + 12) = *(src + 12);
  352. return;
  353. case 14:
  354. #if WIN64
  355. *(long*)dest = *(long*)src;
  356. #else
  357. *(int*)dest = *(int*)src;
  358. *(int*)(dest + 4) = *(int*)(src + 4);
  359. #endif
  360. *(int*)(dest + 8) = *(int*)(src + 8);
  361. *(short*)(dest + 12) = *(short*)(src + 12);
  362. return;
  363. case 15:
  364. #if WIN64
  365. *(long*)dest = *(long*)src;
  366. #else
  367. *(int*)dest = *(int*)src;
  368. *(int*)(dest + 4) = *(int*)(src + 4);
  369. #endif
  370. *(int*)(dest + 8) = *(int*)(src + 8);
  371. *(short*)(dest + 12) = *(short*)(src + 12);
  372. *(dest + 14) = *(src + 14);
  373. return;
  374. case 16:
  375. #if WIN64
  376. *(long*)dest = *(long*)src;
  377. *(long*)(dest + 8) = *(long*)(src + 8);
  378. #else
  379. *(int*)dest = *(int*)src;
  380. *(int*)(dest + 4) = *(int*)(src + 4);
  381. *(int*)(dest + 8) = *(int*)(src + 8);
  382. *(int*)(dest + 12) = *(int*)(src + 12);
  383. #endif
  384. return;
  385. default:
  386. break;
  387. }
  388. // P/Invoke into the native version for large lengths
  389. if (len >= 512) goto PInvoke;
  390. if (((int)dest & 3) != 0)
  391. {
  392. if (((int)dest & 1) != 0)
  393. {
  394. *dest = *src;
  395. src++;
  396. dest++;
  397. len--;
  398. if (((int)dest & 2) == 0)
  399. goto Aligned;
  400. }
  401. *(short *)dest = *(short *)src;
  402. src += 2;
  403. dest += 2;
  404. len -= 2;
  405. Aligned: ;
  406. }
  407. #if WIN64
  408. if (((int)dest & 4) != 0)
  409. {
  410. *(int *)dest = *(int *)src;
  411. src += 4;
  412. dest += 4;
  413. len -= 4;
  414. }
  415. #endif
  416. #if WIN64
  417. ulong count = len / 16;
  418. #else
  419. uint count = len / 16;
  420. #endif
  421. while (count > 0)
  422. {
  423. #if WIN64
  424. ((long*)dest)[0] = ((long*)src)[0];
  425. ((long*)dest)[1] = ((long*)src)[1];
  426. #else
  427. ((int*)dest)[0] = ((int*)src)[0];
  428. ((int*)dest)[1] = ((int*)src)[1];
  429. ((int*)dest)[2] = ((int*)src)[2];
  430. ((int*)dest)[3] = ((int*)src)[3];
  431. #endif
  432. dest += 16;
  433. src += 16;
  434. count--;
  435. }
  436. if ((len & 8) != 0)
  437. {
  438. #if WIN64
  439. ((long*)dest)[0] = ((long*)src)[0];
  440. #else
  441. ((int*)dest)[0] = ((int*)src)[0];
  442. ((int*)dest)[1] = ((int*)src)[1];
  443. #endif
  444. dest += 8;
  445. src += 8;
  446. }
  447. if ((len & 4) != 0)
  448. {
  449. ((int*)dest)[0] = ((int*)src)[0];
  450. dest += 4;
  451. src += 4;
  452. }
  453. if ((len & 2) != 0)
  454. {
  455. ((short*)dest)[0] = ((short*)src)[0];
  456. dest += 2;
  457. src += 2;
  458. }
  459. if ((len & 1) != 0)
  460. *dest = *src;
  461. return;
  462. PInvoke:
  463. _Memmove(dest, src, len);
  464. }
  465. // Non-inlinable wrapper around the QCall that avoids poluting the fast path
  466. // with P/Invoke prolog/epilog.
  467. [SecurityCritical]
  468. [ResourceExposure(ResourceScope.None)]
  469. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  470. [MethodImplAttribute(MethodImplOptions.NoInlining)]
  471. #if WIN64
  472. private unsafe static void _Memmove(byte* dest, byte* src, ulong len)
  473. #else
  474. private unsafe static void _Memmove(byte* dest, byte* src, uint len)
  475. #endif
  476. {
  477. __Memmove(dest, src, len);
  478. }
  479. [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
  480. [SuppressUnmanagedCodeSecurity]
  481. [SecurityCritical]
  482. [ResourceExposure(ResourceScope.None)]
  483. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  484. #if WIN64
  485. extern private unsafe static void __Memmove(byte* dest, byte* src, ulong len);
  486. #else
  487. extern private unsafe static void __Memmove(byte* dest, byte* src, uint len);
  488. #endif
  489. // The attributes on this method are chosen for best JIT performance.
  490. // Please do not edit unless intentional.
  491. [System.Security.SecurityCritical]
  492. [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
  493. [CLSCompliant(false)]
  494. public static unsafe void MemoryCopy(void* source, void* destination, long destinationSizeInBytes, long sourceBytesToCopy)
  495. {
  496. if (sourceBytesToCopy > destinationSizeInBytes)
  497. {
  498. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.sourceBytesToCopy);
  499. }
  500. #if WIN64
  501. Memmove((byte*)destination, (byte*)source, checked((ulong) sourceBytesToCopy));
  502. #else
  503. Memmove((byte*)destination, (byte*)source, checked((uint)sourceBytesToCopy));
  504. #endif // WIN64
  505. }
  506. // The attributes on this method are chosen for best JIT performance.
  507. // Please do not edit unless intentional.
  508. [System.Security.SecurityCritical]
  509. [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
  510. [CLSCompliant(false)]
  511. public static unsafe void MemoryCopy(void* source, void* destination, ulong destinationSizeInBytes, ulong sourceBytesToCopy)
  512. {
  513. if (sourceBytesToCopy > destinationSizeInBytes)
  514. {
  515. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.sourceBytesToCopy);
  516. }
  517. #if WIN64
  518. Memmove((byte*)destination, (byte*)source, sourceBytesToCopy);
  519. #else
  520. Memmove((byte*)destination, (byte*)source, checked((uint)sourceBytesToCopy));
  521. #endif // WIN64
  522. }
  523. #endif
  524. }
  525. }