SimpleMalloc.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #include "SimpleMalloc.h"
  2. #include "Assertions.h"
  3. #include "Types.h"
  4. #include <sys/mman.h>
  5. #include <cstring>
  6. #include <cstdio>
  7. namespace SimpleMalloc {
  8. class AllocationBitmap {
  9. public:
  10. static AllocationBitmap wrap(byte* data, unsigned size)
  11. {
  12. return AllocationBitmap(data, size);
  13. }
  14. ~AllocationBitmap()
  15. {
  16. }
  17. unsigned size() const { return m_size; }
  18. bool get(unsigned index) const
  19. {
  20. ASSERT(index < m_size);
  21. return 0 != (m_data[index / 8] & (1u << (index % 8)));
  22. }
  23. void set(unsigned index, bool value) const
  24. {
  25. ASSERT(index < m_size);
  26. if (value)
  27. m_data[index / 8] |= static_cast<byte>((1u << (index % 8)));
  28. else
  29. m_data[index / 8] &= static_cast<byte>(~(1u << (index % 8)));
  30. }
  31. private:
  32. AllocationBitmap(byte* data, unsigned size)
  33. : m_data(data)
  34. , m_size(size)
  35. {
  36. }
  37. byte* m_data { nullptr };
  38. unsigned m_size { 0 };
  39. };
  40. template<dword chunkSize>
  41. class ChunkAllocator {
  42. public:
  43. void initialize(byte* base)
  44. {
  45. m_base = base;
  46. m_free = capacity_in_allocations();
  47. dump();
  48. }
  49. static constexpr dword capacity_in_allocations()
  50. {
  51. return 1048576 / chunkSize;
  52. }
  53. static constexpr dword capacity_in_bytes()
  54. {
  55. return capacity_in_allocations() * chunkSize;
  56. }
  57. byte* allocate()
  58. {
  59. auto bitmap = this->bitmap();
  60. for (dword i = 0; i < capacity_in_allocations(); ++i) {
  61. if (!bitmap.get(i)) {
  62. bitmap.set(i, true);
  63. --m_free;
  64. return pointer_to_chunk(i);
  65. }
  66. }
  67. return nullptr;
  68. }
  69. void dump() const
  70. {
  71. printf("ChunkAllocator<%u> @ %p, free: %u\n", chunkSize, m_base, m_free);
  72. }
  73. void free(byte* ptr)
  74. {
  75. ASSERT(is_in_allocator(ptr));
  76. auto bitmap = this->bitmap();
  77. auto chunk_index = chunk_index_from_pointer(ptr);
  78. ASSERT(bitmap.get(chunk_index));
  79. bitmap.set(chunk_index, false);
  80. ++m_free;
  81. }
  82. bool is_in_allocator(byte* ptr)
  83. {
  84. return ptr >= pointer_to_chunk(0) && ptr <= address_after_this_allocator();
  85. }
  86. dword chunk_index_from_pointer(byte* ptr)
  87. {
  88. return (ptr - pointer_to_chunk(0)) / chunkSize;
  89. }
  90. byte* pointer_to_chunk(dword index)
  91. {
  92. return m_base + size_of_allocation_bitmap_in_bytes() + (index * chunkSize);
  93. }
  94. AllocationBitmap bitmap()
  95. {
  96. return AllocationBitmap::wrap(m_base, capacity_in_allocations());
  97. }
  98. static constexpr dword size_of_allocation_bitmap_in_bytes()
  99. {
  100. return capacity_in_allocations() / 8;
  101. }
  102. byte* address_after_this_allocator() const
  103. {
  104. return m_base + size_of_allocation_bitmap_in_bytes() + capacity_in_bytes();
  105. }
  106. dword number_of_free_chunks() const
  107. {
  108. return m_free;
  109. }
  110. private:
  111. byte* m_base { nullptr };
  112. dword m_free { capacity_in_allocations() };
  113. };
  114. struct Allocator {
  115. void initialize();
  116. void initialize_if_needed();
  117. void dump();
  118. ChunkAllocator<8> alloc8;
  119. ChunkAllocator<16> alloc16;
  120. ChunkAllocator<4096> alloc4096;
  121. ChunkAllocator<16384> alloc16384;
  122. byte* space;
  123. bool initialized { false };
  124. };
  125. static Allocator allocator;
  126. void Allocator::initialize_if_needed()
  127. {
  128. if (initialized)
  129. return;
  130. initialize();
  131. initialized = true;
  132. }
  133. void Allocator::initialize()
  134. {
  135. space = (byte*)mmap((void*)0x20000000, 32 * MB, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  136. ASSERT(space != MAP_FAILED);
  137. alloc8.initialize(space + 0x10000);
  138. alloc16.initialize(alloc8.address_after_this_allocator());
  139. alloc4096.initialize(alloc16.address_after_this_allocator());
  140. alloc16384.initialize(alloc4096.address_after_this_allocator());
  141. }
  142. void Allocator::dump()
  143. {
  144. alloc8.dump();
  145. alloc16.dump();
  146. alloc4096.dump();
  147. alloc16384.dump();
  148. }
  149. void initialize()
  150. {
  151. allocator.initialize();
  152. }
  153. void dump()
  154. {
  155. allocator.dump();
  156. }
  157. byte* allocate(dword size)
  158. {
  159. if (!size)
  160. return nullptr;
  161. allocator.initialize_if_needed();
  162. if (size <= 8) {
  163. if (auto* ptr = allocator.alloc8.allocate())
  164. return ptr;
  165. }
  166. if (size <= 16) {
  167. if (auto* ptr = allocator.alloc16.allocate())
  168. return ptr;
  169. }
  170. if (size <= 4096) {
  171. if (auto* ptr = allocator.alloc4096.allocate())
  172. return ptr;
  173. }
  174. if (size <= 16384) {
  175. if (auto* ptr = allocator.alloc16384.allocate())
  176. return ptr;
  177. }
  178. printf("SimpleMalloc: unsupported alloc size: %u\n", size);
  179. ASSERT_NOT_REACHED();
  180. return nullptr;
  181. }
  182. byte* allocate_zeroed(dword size)
  183. {
  184. auto* ptr = allocate(size);
  185. if (!ptr)
  186. return nullptr;
  187. memset(ptr, 0, size);
  188. return ptr;
  189. }
  190. byte* reallocate(byte* ptr, dword size)
  191. {
  192. // FIXME;
  193. (void) ptr;
  194. (void) size;
  195. ASSERT_NOT_REACHED();
  196. return nullptr;
  197. }
  198. void free(byte* ptr)
  199. {
  200. if (!ptr)
  201. return;
  202. allocator.initialize_if_needed();
  203. if (allocator.alloc8.is_in_allocator(ptr)) {
  204. allocator.alloc8.free(ptr);
  205. return;
  206. }
  207. if (allocator.alloc16.is_in_allocator(ptr)) {
  208. allocator.alloc16.free(ptr);
  209. return;
  210. }
  211. if (allocator.alloc4096.is_in_allocator(ptr)) {
  212. allocator.alloc4096.free(ptr);
  213. return;
  214. }
  215. if (allocator.alloc16384.is_in_allocator(ptr)) {
  216. allocator.alloc16384.free(ptr);
  217. return;
  218. }
  219. ASSERT_NOT_REACHED();
  220. }
  221. }