MemoryUtils.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #pragma once
  2. #include <stdint.h>
  3. #include "xxhash.h"
  4. namespace il2cpp
  5. {
  6. namespace utils
  7. {
  8. class MemoryUtils
  9. {
  10. public:
  11. IL2CPP_NO_INLINE inline static int MemoryCompareByteByByte(const uint8_t* left, const uint8_t* right, size_t size)
  12. {
  13. for (size_t i = 0; i < size; i++)
  14. {
  15. uint8_t leftItem = left[i];
  16. uint8_t rightItem = right[i];
  17. if (leftItem != rightItem)
  18. {
  19. if (leftItem < rightItem)
  20. return -1;
  21. return 1;
  22. }
  23. }
  24. return 0;
  25. }
  26. inline static int MemoryCompare(const void* left, const void* right, size_t size)
  27. {
  28. const uint8_t* leftBytes = static_cast<const uint8_t*>(left);
  29. const uint8_t* rightBytes = static_cast<const uint8_t*>(right);
  30. ptrdiff_t leftUnalignedByteCount = (reinterpret_cast<intptr_t>(leftBytes + 3) & ~3) - reinterpret_cast<intptr_t>(leftBytes);
  31. ptrdiff_t rightUnalignedByteCount = (reinterpret_cast<intptr_t>(rightBytes + 3) & ~3) - reinterpret_cast<intptr_t>(rightBytes);
  32. // Memory is aligned differently, so the best we can do is byte by byte comparison
  33. if (leftUnalignedByteCount != rightUnalignedByteCount)
  34. return MemoryCompareByteByByte(leftBytes, rightBytes, size);
  35. // Memory is aligned at same size of 4 boundaries, but the start is not at size of 4 alignment
  36. // In this case, we will scan first unaligned number of bytes and then continue with scanning multiples of 4
  37. if (leftUnalignedByteCount != 0)
  38. {
  39. int unalignedMemoryCompare = MemoryCompareByteByByte(leftBytes, rightBytes, leftUnalignedByteCount);
  40. if (unalignedMemoryCompare != 0)
  41. return unalignedMemoryCompare;
  42. leftBytes += leftUnalignedByteCount;
  43. rightBytes += leftUnalignedByteCount;
  44. size -= leftUnalignedByteCount;
  45. }
  46. size_t count4 = size / 4;
  47. for (size_t i = 0; i < count4; i++)
  48. {
  49. uint32_t leftItem = reinterpret_cast<const uint32_t*>(leftBytes)[i];
  50. uint32_t rightItem = reinterpret_cast<const uint32_t*>(rightBytes)[i];
  51. if (leftItem != rightItem)
  52. {
  53. if (leftItem < rightItem)
  54. return -1;
  55. return 1;
  56. }
  57. }
  58. size_t offset = count4 * 4;
  59. return MemoryCompareByteByByte(leftBytes + offset, rightBytes + offset, size - offset);
  60. }
  61. inline static void* MemorySet(void* targetMemory, int value, size_t size)
  62. {
  63. uint8_t* ptr = static_cast<uint8_t*>(targetMemory);
  64. for (size_t i = 0; i != size; i++)
  65. {
  66. ptr[i] = static_cast<uint8_t>(value);
  67. }
  68. return targetMemory;
  69. }
  70. inline static void MemoryCopyByteByByte(uint8_t* target, const uint8_t* source, size_t size)
  71. {
  72. for (size_t i = 0; i < size; i++)
  73. target[i] = source[i];
  74. }
  75. inline static void* MemoryCopy(void* target, const void* source, size_t size)
  76. {
  77. uint8_t* targetBytes = static_cast<uint8_t*>(target);
  78. const uint8_t* sourceBytes = static_cast<const uint8_t*>(source);
  79. ptrdiff_t targetUnalignedByteCount = (reinterpret_cast<intptr_t>(targetBytes + 3) & ~3) - reinterpret_cast<intptr_t>(targetBytes);
  80. ptrdiff_t sourceUnalignedByteCount = (reinterpret_cast<intptr_t>(sourceBytes + 3) & ~3) - reinterpret_cast<intptr_t>(sourceBytes);
  81. // Memory is aligned differently, so the best we can do is byte by byte copy
  82. if (targetUnalignedByteCount != sourceUnalignedByteCount)
  83. {
  84. MemoryCopyByteByByte(targetBytes, sourceBytes, size);
  85. return targetBytes;
  86. }
  87. // Memory is aligned at same size of 4 boundaries, but the start is not at size of 4 alignment
  88. // In this case, we will copy first unaligned number of bytes and then continue with copying multiples of 4
  89. if (targetUnalignedByteCount != 0)
  90. {
  91. MemoryCopyByteByByte(targetBytes, sourceBytes, targetUnalignedByteCount);
  92. targetBytes += targetUnalignedByteCount;
  93. sourceBytes += targetUnalignedByteCount;
  94. size -= targetUnalignedByteCount;
  95. }
  96. size_t count4 = size / 4;
  97. const uint32_t* source32 = reinterpret_cast<const uint32_t*>(sourceBytes);
  98. uint32_t* target32 = reinterpret_cast<uint32_t*>(targetBytes);
  99. for (size_t i = 0; i < count4; i++)
  100. target32[i] = source32[i];
  101. size_t offset = count4 * 4;
  102. MemoryCopyByteByByte(targetBytes + offset, sourceBytes + offset, size - offset);
  103. return target;
  104. }
  105. template<typename T>
  106. static int32_t MemCmpRef(T* left, T* right)
  107. {
  108. return MemoryCompare(left, right, sizeof(T));
  109. }
  110. #if IL2CPP_TINY
  111. template<typename T>
  112. static int32_t MemHashRef(T* val)
  113. {
  114. return XXH32(val, sizeof(T), 0x8f37154b);
  115. }
  116. #endif
  117. };
  118. #define DECL_MEMCMP_NUM(typ) template<> inline int32_t MemoryUtils::MemCmpRef<typ>(typ* left, typ* right) { return (*right > *left) ? -1 : (*right < *left) ? 1 : 0; }
  119. DECL_MEMCMP_NUM(int8_t)
  120. DECL_MEMCMP_NUM(int16_t)
  121. DECL_MEMCMP_NUM(int32_t)
  122. DECL_MEMCMP_NUM(int64_t)
  123. DECL_MEMCMP_NUM(uint8_t)
  124. DECL_MEMCMP_NUM(uint16_t)
  125. DECL_MEMCMP_NUM(uint32_t)
  126. DECL_MEMCMP_NUM(uint64_t)
  127. // don't think this will give the right result for NaNs and such
  128. DECL_MEMCMP_NUM(float)
  129. DECL_MEMCMP_NUM(double)
  130. #undef DECL_MEMCMP_NUM
  131. #define DECL_MEMHASH_NUM(typ) template<> inline int32_t MemoryUtils::MemHashRef(typ* val) { return (int32_t)(*val); }
  132. DECL_MEMHASH_NUM(int8_t)
  133. DECL_MEMHASH_NUM(int16_t)
  134. DECL_MEMHASH_NUM(int32_t)
  135. DECL_MEMHASH_NUM(uint8_t)
  136. DECL_MEMHASH_NUM(uint16_t)
  137. DECL_MEMHASH_NUM(uint32_t)
  138. DECL_MEMHASH_NUM(float)
  139. #undef DECL_MEMHASH_NUM
  140. template<> inline int32_t MemoryUtils::MemHashRef(int64_t* val) { int64_t k = *val; return (int32_t)(k & 0xffffffff) ^ (int32_t)((k >> 32) & 0xffffffff); }
  141. template<> inline int32_t MemoryUtils::MemHashRef(uint64_t* val) { return MemHashRef(reinterpret_cast<int64_t*>(val)); }
  142. template<> inline int32_t MemoryUtils::MemHashRef(double* val) { return MemHashRef(reinterpret_cast<int64_t*>(val)); }
  143. } // namespace utils
  144. } // namespace il2cpp