codemod 2010-2016 to 2010-present
[hiphop-php.git] / hphp / util / arena.cpp
blob50433fff6d7eff173f712941a447060b9e3d4059
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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/malloc-size-class.h"
20 namespace HPHP {
22 //////////////////////////////////////////////////////////////////////
24 namespace {
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 "
38 "malloc size class");
39 static_assert((kChunkBytes & (kMinBytes - 1)) == 0,
40 "kChunkBytes must be multiple of kMinBytes");
42 memset(&m_frame, 0, sizeof m_frame);
43 m_current = static_cast<char*>(malloc(kChunkBytes));
44 m_ptrs.push_back(m_current);
45 m_bypassSlabAlloc = s_bypassSlabAlloc;
46 #ifdef DEBUG
47 m_externalAllocSize = 0;
48 #endif
51 template<size_t kChunkBytes>
52 ArenaImpl<kChunkBytes>::~ArenaImpl() {
53 for (size_t i = 0, sz = m_ptrs.size(); i < sz; ++i) {
54 free(m_ptrs[i]);
56 for (size_t i = 0, sz = m_externalPtrs.size(); i < sz; ++i) {
57 free(m_externalPtrs.get(i));
61 template<size_t kChunkBytes>
62 size_t ArenaImpl<kChunkBytes>::size() const {
63 size_t ret = m_ptrs.size() * kChunkBytes - slackEstimate();
64 #ifdef DEBUG
65 ret += m_externalAllocSize;
66 #endif
67 return ret;
70 template<size_t kChunkBytes>
71 void* ArenaImpl<kChunkBytes>::allocSlow(size_t nbytes) {
72 // Large allocations go directly to malloc without discarding our
73 // current chunk.
74 if (UNLIKELY(nbytes >= kChunkBytes || m_bypassSlabAlloc)) {
75 #if defined(VALGRIND) || !defined(USE_JEMALLOC)
76 // We want all our pointers to be kMinBytes - 1 byte aligned.
77 // Without jemalloc we have to do that by hand.
78 auto extra = kMinBytes - 1;
79 #else
80 auto extra = 0;
81 #endif
83 char* ptr = static_cast<char*>(malloc(nbytes + extra));
84 #ifdef DEBUG
85 m_externalAllocSize += nbytes + extra;
86 #endif
87 m_externalPtrs.push(ptr); // save ptr before aligning it
88 // align up to (extra + 1) bytes
89 ptr = (char*)((uintptr_t(ptr) + extra) & ~extra);
90 assert((intptr_t(ptr) & (kMinBytes - 1)) == 0);
91 return ptr;
93 createSlab();
94 return alloc(nbytes);
97 template<size_t kChunkBytes>
98 void ArenaImpl<kChunkBytes>::createSlab() {
99 ++m_frame.index;
100 m_frame.offset = m_bypassSlabAlloc ? kChunkBytes : 0 ;
101 if (m_frame.index < m_ptrs.size()) {
102 m_current = m_ptrs[m_frame.index];
103 } else {
104 m_current = static_cast<char*>(malloc(kChunkBytes));
105 m_ptrs.push_back(m_current);
107 assert((intptr_t(m_current) & (kMinBytes - 1)) == 0);
110 //////////////////////////////////////////////////////////////////////
112 template struct ArenaImpl<4096>;
113 template struct ArenaImpl<32 * 1024>;
115 //////////////////////////////////////////////////////////////////////