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 +----------------------------------------------------------------------+
16 #include "hphp/util/arena.h"
17 #include "hphp/util/assertions.h"
18 #include "hphp/util/jemalloc-util.h"
22 //////////////////////////////////////////////////////////////////////
25 bool s_bypassSlabAlloc
= false;
28 void SetArenaSlabAllocBypass(bool f
) {
29 s_bypassSlabAlloc
= f
;
32 template<size_t kChunkBytes
>
33 ArenaImpl
<kChunkBytes
>::ArenaImpl() {
34 static_assert(kChunkBytes
<= 4294967295U,
35 "Arena slab size may not be larger than UINT32_MAX");
36 static_assert(is_malloc_size_class
<kChunkBytes
>::value
,
37 "ArenaImpl instantiated with size that was not a "
39 static_assert((kChunkBytes
& (kMinBytes
- 1)) == 0,
40 "kChunkBytes must be multiple of kMinBytes");
43 m_current
= static_cast<char*>(malloc(kChunkBytes
));
44 m_ptrs
.push_back(m_current
);
46 m_bypassSlabAlloc
= s_bypassSlabAlloc
;
48 m_externalAllocSize
= 0;
52 template<size_t kChunkBytes
>
53 ArenaImpl
<kChunkBytes
>::~ArenaImpl() {
54 for (auto d
= m_dtors
; d
!= nullptr; d
= d
->next
) {
57 for (size_t i
= 0, sz
= m_ptrs
.size(); i
< sz
; ++i
) {
60 for (size_t i
= 0, sz
= m_externalPtrs
.size(); i
< sz
; ++i
) {
61 free(m_externalPtrs
.get(i
));
65 template<size_t kChunkBytes
>
66 size_t ArenaImpl
<kChunkBytes
>::size() const {
67 size_t ret
= m_ptrs
.size() * kChunkBytes
- slackEstimate();
69 ret
+= m_externalAllocSize
;
74 template<size_t kChunkBytes
>
75 void* ArenaImpl
<kChunkBytes
>::allocSlow(size_t nbytes
) {
76 // Large allocations go directly to malloc without discarding our
78 if (UNLIKELY(nbytes
>= kChunkBytes
|| m_bypassSlabAlloc
)) {
79 #if defined(VALGRIND) || !defined(USE_JEMALLOC)
80 // We want all our pointers to be kMinBytes - 1 byte aligned.
81 // Without jemalloc we have to do that by hand.
82 auto extra
= kMinBytes
- 1;
87 char* ptr
= static_cast<char*>(malloc(nbytes
+ extra
));
89 m_externalAllocSize
+= nbytes
+ extra
;
91 m_externalPtrs
.push(ptr
); // save ptr before aligning it
92 // align up to (extra + 1) bytes
93 ptr
= (char*)((uintptr_t(ptr
) + extra
) & ~extra
);
94 assert((intptr_t(ptr
) & (kMinBytes
- 1)) == 0);
101 template<size_t kChunkBytes
>
102 void ArenaImpl
<kChunkBytes
>::createSlab() {
103 m_offset
= m_bypassSlabAlloc
? kChunkBytes
: 0 ;
104 m_current
= static_cast<char*>(malloc(kChunkBytes
));
105 m_ptrs
.push_back(m_current
);
106 assert((intptr_t(m_current
) & (kMinBytes
- 1)) == 0);
109 //////////////////////////////////////////////////////////////////////
111 template struct ArenaImpl
<4096>;
112 template struct ArenaImpl
<32 * 1024>;
114 //////////////////////////////////////////////////////////////////////