2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_UTIL_ARENA_H_
17 #define incl_HPHP_UTIL_ARENA_H_
23 #include "hphp/util/pointer-list.h"
27 //////////////////////////////////////////////////////////////////////
30 * Arena/ArenaImpl is an allocator that frees all memory when the
31 * arena instance is destroyed. No destructors of allocated objects
32 * will be called! It is a bump-pointer allocator.
34 * At various points in the lifetime of the arena, you can introduce a
35 * new `frame' by calling beginFrame. This is essentially a marker of
36 * the current allocator state, which you can pop back to by calling
39 * Allocations smaller than kMinBytes bytes are rounded up to kMinBytes, and
40 * all allocations are kMinBytes-aligned.
42 * Allocations larger than kChunkBytes are acquired directly from
43 * malloc, and don't (currently) get freed with frames.
45 * The Arena typedef is for convenience when you want a default
46 * configuration. Use ArenaImpl if you want something specific.
48 template<size_t kChunkBytes
> class ArenaImpl
;
49 typedef ArenaImpl
<4096> Arena
;
51 //////////////////////////////////////////////////////////////////////
53 template<size_t kChunkBytes
>
55 static const size_t kMinBytes
= 8;
61 void* alloc(size_t nbytes
);
64 * Return the amount of memory this arena has handed out via alloc().
69 * Return the amount of memory the arena has allocated, but not yet
70 * handed out via alloc(). This can be used to estimate memory
71 * usage ignoring arena overhead.
73 * Note that this is only an estimate, because we will include
74 * fragmentation on the ends of slabs or due to alignment.
76 size_t slackEstimate() const { return kChunkBytes
- m_frame
.offset
; }
79 * Framed arena allocation.
81 * Nesting allocations between beginFrame() and endFrame() will
82 * release memory in a stack-like fashion. Calling endFrame() more
83 * times than beginFrame() will break things.
85 * Chunks allocated larger than kChunkBytes are not freed until the
86 * entire arena is destroyed.
88 * Memory is not released back to malloc until the entire arena is
95 // copying Arenas will end badly.
96 ArenaImpl(const ArenaImpl
&);
97 ArenaImpl
& operator=(const ArenaImpl
&);
107 void* allocSlow(size_t nbytes
);
113 std::vector
<char*> m_ptrs
;
114 PointerList
<char> m_externalPtrs
;
115 bool m_bypassSlabAlloc
;
117 size_t m_externalAllocSize
;
121 //////////////////////////////////////////////////////////////////////
123 template<size_t kChunkBytes
>
124 inline void* ArenaImpl
<kChunkBytes
>::alloc(size_t nbytes
) {
125 nbytes
= (nbytes
+ (kMinBytes
- 1)) & ~(kMinBytes
- 1); // round up
126 size_t newOff
= m_frame
.offset
+ nbytes
;
127 if (newOff
<= kChunkBytes
) {
128 char* ptr
= m_current
+ m_frame
.offset
;
129 m_frame
.offset
= newOff
;
132 return allocSlow(nbytes
);
135 template<size_t kChunkBytes
>
136 inline void ArenaImpl
<kChunkBytes
>::beginFrame() {
137 Frame curFrame
= m_frame
; // don't include the Frame allocation
138 Frame
* oldFrame
= static_cast<Frame
*>(alloc(sizeof(Frame
)));
139 *oldFrame
= curFrame
;
140 m_frame
.prev
= oldFrame
;
143 template<size_t kChunkBytes
>
144 inline void ArenaImpl
<kChunkBytes
>::endFrame() {
145 assert(m_frame
.prev
);
146 m_frame
= *m_frame
.prev
;
147 m_current
= m_ptrs
[m_frame
.index
];
150 void SetArenaSlabAllocBypass(bool f
);
152 //////////////////////////////////////////////////////////////////////
156 // These global-operator-new declarations cannot be in a namespace,
157 // but since they take Arena arguments we won't overload anything else.
159 template<size_t kChunkBytes
>
160 inline void* operator new(size_t nbytes
,
161 HPHP::ArenaImpl
<kChunkBytes
>& a
) {
162 return a
.alloc(nbytes
);
165 template<size_t kChunkBytes
>
166 inline void* operator new[](size_t nbytes
,
167 HPHP::ArenaImpl
<kChunkBytes
>& a
) {
168 return a
.alloc(nbytes
);
171 //////////////////////////////////////////////////////////////////////