2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 +----------------------------------------------------------------------+
22 #include "hphp/util/pointer-list.h"
26 //////////////////////////////////////////////////////////////////////
29 * Arena/ArenaImpl is an allocator that frees all its memory when the arena
30 * instance is destroyed. It is a bump-pointer allocator.
32 * There are two main methods to allocate memory from the arena:
33 * 1) alloc() allocates raw memory for which no destructor is invoked when the
35 * 2) allocD<C>() allocates memory for an object of class C, whose destructor
36 * (or a custom callback) is invoked when the arena is destroyed.
38 * Allocations smaller than kMinBytes bytes are rounded up to kMinBytes, and
39 * all allocations are kMinBytes-aligned.
41 * Allocations larger than kChunkBytes are acquired directly from
44 * The Arena typedef is for convenience when you want a default
45 * configuration. Use ArenaImpl if you want something specific.
47 template<size_t kChunkBytes
> struct ArenaImpl
;
48 typedef ArenaImpl
<4096> Arena
;
50 //////////////////////////////////////////////////////////////////////
52 template<size_t kChunkBytes
>
59 * Allocate a raw chunk of memory with `nbytes' bytes. No destructors will be
60 * called when the arena is destroyed.
62 void* alloc(size_t nbytes
);
65 * Allocate a chunk of memory large enough to hold an object of class C, and
66 * register a destructor to be invoked when the arena is destroyed. A custom
67 * `dtor' to be invoked can be provided, otherwise C's destructor is invoked.
72 template<class C
, class D
>
76 * Return the amount of memory this arena has handed out via alloc().
81 * Return the amount of memory the arena has allocated, but not yet
82 * handed out via alloc(). This can be used to estimate memory
83 * usage ignoring arena overhead.
85 * Note that this is only an estimate, because we will include
86 * fragmentation on the ends of slabs or due to alignment.
88 size_t slackEstimate() const { return kChunkBytes
- m_offset
; }
97 // copying Arenas will end badly.
98 ArenaImpl(const ArenaImpl
&);
99 ArenaImpl
& operator=(const ArenaImpl
&);
101 static const size_t kMinBytes
= 8;
103 void* allocSlow(size_t nbytes
);
108 std::vector
<char*> m_ptrs
;
109 PointerList
<char> m_externalPtrs
;
111 bool m_bypassSlabAlloc
;
113 size_t m_externalAllocSize
;
117 //////////////////////////////////////////////////////////////////////
119 template<size_t kChunkBytes
>
120 inline void* ArenaImpl
<kChunkBytes
>::alloc(size_t nbytes
) {
121 nbytes
= (nbytes
+ (kMinBytes
- 1)) & ~(kMinBytes
- 1); // round up
122 size_t newOff
= m_offset
+ nbytes
;
123 if (newOff
<= kChunkBytes
) {
124 char* ptr
= m_current
+ m_offset
;
128 return allocSlow(nbytes
);
131 template<size_t kChunkBytes
>
132 template<class C
, class D
>
133 inline C
* ArenaImpl
<kChunkBytes
>::allocD(D dtor
) {
134 auto ptr
= (C
*)alloc(sizeof(C
));
135 auto dtorPtr
= (Destroyer
*)alloc(sizeof(Destroyer
));
137 dtorPtr
->dtor
= dtor
;
138 dtorPtr
->next
= m_dtors
;
143 template<size_t kChunkBytes
>
145 inline C
* ArenaImpl
<kChunkBytes
>::allocD() {
146 return allocD([](void* p
) { static_cast<C
*>(p
)->~C(); });
149 void SetArenaSlabAllocBypass(bool f
);
151 //////////////////////////////////////////////////////////////////////
155 // These global-operator-new declarations cannot be in a namespace,
156 // but since they take Arena arguments we won't overload anything else.
158 template<size_t kChunkBytes
>
159 inline void* operator new(size_t nbytes
,
160 HPHP::ArenaImpl
<kChunkBytes
>& a
) {
161 return a
.alloc(nbytes
);
164 template<size_t kChunkBytes
>
165 inline void* operator new[](size_t nbytes
,
166 HPHP::ArenaImpl
<kChunkBytes
>& a
) {
167 return a
.alloc(nbytes
);
170 //////////////////////////////////////////////////////////////////////