This fixes a bug in PHP/HH's crypt_blowfish implementation that can cause a short...
[hiphop-php.git] / hphp / util / arena.cpp
blobf4dbaacea86c12e54a8e07406bf1ebc0b46a12dd
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/jemalloc-util.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 m_offset = 0;
43 m_current = static_cast<char*>(malloc(kChunkBytes));
44 m_ptrs.push_back(m_current);
45 m_dtors = nullptr;
46 m_bypassSlabAlloc = s_bypassSlabAlloc;
47 #ifndef NDEBUG
48 m_externalAllocSize = 0;
49 #endif
52 template<size_t kChunkBytes>
53 ArenaImpl<kChunkBytes>::~ArenaImpl() {
54 for (auto d = m_dtors; d != nullptr; d = d->next) {
55 d->dtor(d->obj);
57 for (size_t i = 0, sz = m_ptrs.size(); i < sz; ++i) {
58 free(m_ptrs[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();
68 #ifndef NDEBUG
69 ret += m_externalAllocSize;
70 #endif
71 return ret;
74 template<size_t kChunkBytes>
75 void* ArenaImpl<kChunkBytes>::allocSlow(size_t nbytes) {
76 // Large allocations go directly to malloc without discarding our
77 // current chunk.
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;
83 #else
84 auto extra = 0;
85 #endif
87 char* ptr = static_cast<char*>(malloc(nbytes + extra));
88 #ifndef NDEBUG
89 m_externalAllocSize += nbytes + extra;
90 #endif
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);
95 return ptr;
97 createSlab();
98 return alloc(nbytes);
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 //////////////////////////////////////////////////////////////////////