• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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