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