1 //===- Allocators.h ---------------------------------------------------------===// 2 // 3 // The MCLinker Project 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef LLVM_ALLOCATORS_H 11 #define LLVM_ALLOCATORS_H 12 #ifdef ENABLE_UNITTEST 13 #include <gtest.h> 14 #endif 15 #include "mcld/ADT/Uncopyable.h" 16 #include "mcld/ADT/TypeTraits.h" 17 #include "mcld/LD/LDContext.h" 18 19 #include <cstddef> 20 #include <cstdlib> 21 22 namespace mcld 23 { 24 25 /** \class Chunk 26 * \brief Chunk is the basic unit of the storage of the LinearAllocator 27 * 28 * @see LinearAllocator 29 */ 30 template<typename DataType, size_t ChunkSize> 31 struct Chunk 32 { 33 public: 34 typedef DataType value_type; 35 public: ChunkChunk36 Chunk() 37 : next(0), bound(0) 38 { } 39 sizeChunk40 static size_t size() { return ChunkSize; } 41 42 public: 43 Chunk* next; 44 size_t bound; 45 DataType data[ChunkSize]; 46 }; 47 48 template<typename DataType> 49 struct Chunk<DataType, 0> 50 { 51 public: 52 typedef DataType value_type; 53 54 public: 55 Chunk() 56 : next(0), bound(0) { 57 if (0 != m_Size) 58 data = (DataType*)malloc(sizeof(DataType)*m_Size); 59 else 60 data = 0; 61 } 62 63 ~Chunk() { 64 if (data) 65 free(data); 66 } 67 68 static size_t size() { return m_Size; } 69 static void setSize(size_t pSize) { m_Size = pSize; } 70 71 public: 72 Chunk* next; 73 size_t bound; 74 DataType *data; 75 static size_t m_Size; 76 }; 77 78 template<typename DataType> 79 size_t Chunk<DataType, 0>::m_Size = 0; 80 81 template<typename ChunkType> 82 class LinearAllocatorBase : private Uncopyable 83 { 84 public: 85 typedef ChunkType chunk_type; 86 typedef typename ChunkType::value_type value_type; 87 typedef typename ChunkType::value_type* pointer; 88 typedef typename ChunkType::value_type& reference; 89 typedef const typename ChunkType::value_type* const_pointer; 90 typedef const typename ChunkType::value_type& const_reference; 91 typedef size_t size_type; 92 typedef ptrdiff_t difference_type; 93 typedef unsigned char byte_type; 94 95 protected: 96 LinearAllocatorBase() 97 : m_pRoot(0), 98 m_pCurrent(0), 99 m_AllocatedNum(0) { 100 } 101 102 // LinearAllocatorBase does NOT mean to destroy the allocated memory. 103 // If you want a memory allocator to release memory at destruction, please 104 // use GCFactory series. 105 virtual ~LinearAllocatorBase() 106 { } 107 108 public: 109 pointer address(reference X) const 110 { return &X; } 111 112 const_pointer address(const_reference X) const 113 { return &X; } 114 115 /// standard construct - constructing an object on the location pointed by 116 // pPtr, and using its copy constructor to initialized its value to pValue. 117 // 118 // @param pPtr the address where the object to be constructed 119 // @param pValue the value to be constructed 120 void construct(pointer pPtr, const_reference pValue) 121 { new (pPtr) value_type(pValue); } 122 123 /// default construct - constructing an object on the location pointed by 124 // pPtr, and using its default constructor to initialized its value to 125 // pValue. 126 // 127 // @param pPtr the address where the object to be constructed 128 void construct(pointer pPtr) 129 { new (pPtr) value_type(); } 130 131 /// standard destroy - destroy data on arbitrary address 132 // @para pPtr the address where the data to be destruected. 133 void destroy(pointer pPtr) 134 { pPtr->~value_type(); } 135 136 /// allocate - allocate N data in order. 137 // - Disallow to allocate a chunk whose size is bigger than a chunk. 138 // 139 // @param N the number of allocated data. 140 // @return the start address of the allocated memory 141 pointer allocate(size_type N) { 142 if (0 == N || N > chunk_type::size()) 143 return 0; 144 145 if (empty()) 146 initialize(); 147 148 size_type rest_num_elem = chunk_type::size() - m_pCurrent->bound; 149 pointer result = 0; 150 if (N > rest_num_elem) 151 createChunk(); 152 result = const_cast<pointer>(&(m_pCurrent->data[m_pCurrent->bound])); 153 m_pCurrent->bound += N; 154 return result; 155 } 156 157 /// allocate - clone function of allocating one datum. 158 pointer allocate() { 159 if (empty()) 160 initialize(); 161 162 pointer result = 0; 163 if (chunk_type::size() == m_pCurrent->bound) 164 createChunk(); 165 result = const_cast<pointer>(&(m_pCurrent->data[m_pCurrent->bound])); 166 ++m_pCurrent->bound; 167 return result; 168 } 169 170 /// deallocate - deallocate N data from the pPtr 171 // - if we can simply release some memory, then do it. Otherwise, do 172 // nothing. 173 void deallocate(pointer &pPtr, size_type N) { 174 if (0 == N || 175 N > chunk_type::size() || 176 0 == m_pCurrent->bound || 177 N >= m_pCurrent->bound) 178 return; 179 if (!isAvailable(pPtr)) 180 return; 181 m_pCurrent->bound -= N; 182 pPtr = 0; 183 } 184 185 /// deallocate - clone function of deallocating one datum 186 void deallocate(pointer &pPtr) { 187 if (0 == m_pCurrent->bound) 188 return; 189 if (!isAvailable(pPtr)) 190 return; 191 m_pCurrent->bound -= 1; 192 pPtr = 0; 193 } 194 195 /// isIn - whether the pPtr is in the current chunk? 196 bool isIn(pointer pPtr) const { 197 if (pPtr >= &(m_pCurrent->data[0]) && 198 pPtr <= &(m_pCurrent->data[chunk_type::size()-1])) 199 return true; 200 return false; 201 } 202 203 /// isIn - whether the pPtr is allocated, and can be constructed. 204 bool isAvailable(pointer pPtr) const { 205 if (pPtr >= &(m_pCurrent->data[m_pCurrent->bound]) && 206 pPtr <= &(m_pCurrent->data[chunk_type::size()-1])) 207 return true; 208 return false; 209 } 210 211 void reset() { 212 m_pRoot = 0; 213 m_pCurrent = 0; 214 m_AllocatedNum = 0; 215 } 216 217 /// clear - clear all chunks 218 void clear() { 219 chunk_type *cur = m_pRoot, *prev; 220 while (0 != cur) { 221 unsigned int idx=0; 222 prev = cur; 223 cur = cur->next; 224 while (idx != prev->bound) { 225 destroy(&prev->data[idx]); 226 ++idx; 227 } 228 delete prev; 229 } 230 reset(); 231 } 232 233 // ----- observers ----- // 234 bool empty() const { 235 return (0 == m_pRoot); 236 } 237 238 size_type max_size() const 239 { return m_AllocatedNum; } 240 241 protected: 242 inline void initialize() { 243 m_pRoot = new chunk_type(); 244 m_pCurrent = m_pRoot; 245 m_AllocatedNum += chunk_type::size(); 246 } 247 248 inline chunk_type *createChunk() { 249 chunk_type *result = new chunk_type(); 250 m_pCurrent->next = result; 251 m_pCurrent = result; 252 m_AllocatedNum += chunk_type::size(); 253 return result; 254 } 255 256 protected: 257 chunk_type *m_pRoot; 258 chunk_type *m_pCurrent; 259 size_type m_AllocatedNum; 260 }; 261 262 /** \class LinearAllocator 263 * \brief LinearAllocator is another bump pointer allocator which should be 264 * limited in use of two-phase memory allocation. 265 * 266 * Two-phase memory allocation clear separates the use of memory into 'claim' 267 * and 'release' phases. There are no interleaving allocation and 268 * deallocation. Interleaving 'allocate' and 'deallocate' increases the size 269 * of allocated memory, and causes bad locality. 270 * 271 * The underlying concept of LinearAllocator is a memory pool. LinearAllocator 272 * is a simple implementation of boost::pool's ordered_malloc() and 273 * ordered_free(). 274 * 275 * template argument DataType is the DataType to be allocated 276 * template argument ChunkSize is the number of bytes of a chunk 277 */ 278 template<typename DataType, size_t ChunkSize> 279 class LinearAllocator : public LinearAllocatorBase<Chunk<DataType, ChunkSize> > 280 { 281 public: 282 template<typename NewDataType> 283 struct rebind { 284 typedef LinearAllocator<NewDataType, ChunkSize> other; 285 }; 286 287 public: 288 LinearAllocator() 289 : LinearAllocatorBase<Chunk<DataType, ChunkSize> >() { 290 } 291 292 virtual ~LinearAllocator() 293 { } 294 }; 295 296 template<typename DataType> 297 class LinearAllocator<DataType, 0> : public LinearAllocatorBase<Chunk<DataType, 0> > 298 { 299 public: 300 template<typename NewDataType> 301 struct rebind { 302 typedef LinearAllocator<NewDataType, 0> other; 303 }; 304 305 public: 306 explicit LinearAllocator(size_t pNum) 307 : LinearAllocatorBase<Chunk<DataType, 0> >() { 308 Chunk<DataType, 0>::setSize(pNum); 309 } 310 311 virtual ~LinearAllocator() 312 { } 313 }; 314 315 template<typename DataType> 316 class MallocAllocator 317 { 318 public: 319 typedef size_t size_type; 320 typedef ptrdiff_t difference_type; 321 typedef DataType* pointer; 322 typedef const DataType* const_pointer; 323 typedef DataType& reference; 324 typedef const DataType& const_reference; 325 typedef DataType value_type; 326 327 template<typename OtherDataType> 328 struct rebind 329 { 330 typedef MallocAllocator<OtherDataType> other; 331 }; 332 333 public: 334 MallocAllocator() throw() 335 { } 336 337 MallocAllocator(const MallocAllocator&) throw() 338 { } 339 340 ~MallocAllocator() throw() 341 { } 342 343 pointer address(reference X) const 344 { return &X; } 345 346 const_pointer address(const_reference X) const 347 { return &X; } 348 349 pointer allocate(size_type pNumOfElements, const void* = 0) 350 { 351 return static_cast<DataType*>( 352 std::malloc(pNumOfElements*sizeof(DataType))); 353 } 354 355 void deallocate(pointer pObject, size_type) 356 { std::free(static_cast<void*>(pObject)); } 357 358 size_type max_size() const throw() 359 { return size_t(-1) / sizeof(DataType); } 360 361 void construct(pointer pObject, const DataType& pValue) 362 { ::new((void *)pObject) value_type(pValue); } 363 364 void destroy(pointer pObject) 365 { pObject->~DataType(); } 366 367 }; 368 369 template<> 370 class MallocAllocator<void> 371 { 372 public: 373 typedef size_t size_type; 374 typedef ptrdiff_t difference_type; 375 typedef void* pointer; 376 typedef const void* const_pointer; 377 typedef void* reference; 378 typedef const void* const_reference; 379 typedef void* value_type; 380 381 template<typename OtherDataType> 382 struct rebind 383 { 384 typedef MallocAllocator<OtherDataType> other; 385 }; 386 387 public: 388 MallocAllocator() throw() 389 { } 390 391 MallocAllocator(const MallocAllocator&) throw() 392 { } 393 394 ~MallocAllocator() throw() 395 { } 396 397 size_type max_size() const throw() 398 { return size_t(-1) / sizeof(void*); } 399 400 pointer address(reference X) const 401 { return X; } 402 403 const_pointer address(const_reference X) const 404 { return X; } 405 406 template<typename DataType> 407 DataType* allocate(size_type pNumOfElements, const void* = 0) { 408 return static_cast<DataType*>( 409 std::malloc(pNumOfElements*sizeof(DataType))); 410 } 411 412 pointer allocate(size_type pNumOfElements, const void* = 0) { 413 return std::malloc(pNumOfElements); 414 } 415 416 template<typename DataType> 417 void deallocate(DataType* pObject, size_type) 418 { std::free(static_cast<void*>(pObject)); } 419 420 void deallocate(pointer pObject, size_type) 421 { std::free(pObject); } 422 423 template<typename DataType> 424 void construct(DataType* pObject, const DataType& pValue) 425 { /* do nothing */ } 426 427 void construct(pointer pObject, const_reference pValue) 428 { /* do nothing */ } 429 430 template<typename DataType> 431 void destroy(DataType* pObject) 432 { /* do nothing */ } 433 434 void destroy(pointer pObject) 435 { /* do nothing */ } 436 }; 437 438 } // namespace mcld 439 440 #endif 441