enable coroutine for rust emitter
[hiphop-php.git] / hphp / util / extent-hooks.cpp
blob99c67a396f41c3fee743322105fbaf87678705ba
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 +----------------------------------------------------------------------+
17 #include "hphp/util/extent-hooks.h"
19 #include "hphp/util/assertions.h"
20 #include "hphp/util/managed-arena.h"
21 #include <folly/portability/SysMman.h>
23 #if USE_JEMALLOC_EXTENT_HOOKS
25 namespace HPHP { namespace alloc {
27 // Trivial jemalloc extent hooks. If a hook always returns true (indicating
28 // failure), setting it to NULL can be more efficient.
30 static bool
31 extent_commit(extent_hooks_t* /*extent_hooks*/, void* /*addr*/, size_t /*size*/,
32 size_t /*offset*/, size_t /*length*/, unsigned /*arena_ind*/) {
33 return false;
36 static bool
37 extent_purge(extent_hooks_t* /*extent_hooks*/, void* addr, size_t size,
38 size_t offset, size_t length, unsigned /*arena_ind*/) {
39 // This function should return false upon success, which is the case when
40 // madvise returns 0.
41 return madvise((char*)addr + offset, length, MADV_DONTNEED);
44 static bool
45 extent_purge_lazy(extent_hooks_t* /*extent_hooks*/, void* addr, size_t size,
46 size_t offset, size_t length, unsigned /*arena_ind*/) {
47 #ifdef MADV_FREE
48 return madvise((char*)addr + offset, length, MADV_FREE);
49 #else
50 return madvise((char*)addr + offset, length, MADV_DONTNEED);
51 #endif
54 static bool extent_split(extent_hooks_t* /*extent_hooks*/, void* /*addr*/,
55 size_t /*size*/, size_t /*sizea*/, size_t /*sizeb*/,
56 bool /*comitted*/, unsigned /*arena_ind*/) {
57 return false;
60 static bool extent_merge(extent_hooks_t* /*extent_hooks*/, void* /*addra*/,
61 size_t /*sizea*/, void* /*addrb*/, size_t /*sizeb*/,
62 bool /*committed*/, unsigned /*arena_ind*/) {
63 return false;
66 extent_hooks_t MultiRangeExtentAllocator::s_hooks {
67 MultiRangeExtentAllocator::extent_alloc,
68 nullptr, // dalloc
69 nullptr, // destroy
70 extent_commit,
71 nullptr, // decommit
72 extent_purge_lazy, // purge_lazy
73 extent_purge, // purge_forced
74 extent_split,
75 extent_merge
78 void MultiRangeExtentAllocator::appendMapper(RangeMapper* m) {
79 for (auto& p : m_mappers) {
80 if (p == nullptr) {
81 p = m;
82 return;
85 throw std::runtime_error{"too many mappers (check kMaxMapperCount)"};
88 size_t MultiRangeExtentAllocator::maxCapacity() const {
89 size_t result = 0;
90 for (auto& p : m_mappers) {
91 if (p == nullptr) {
92 break;
94 result += p->getRangeState().capacity();
96 return result;
100 void* MultiRangeExtentAllocator::
101 extent_alloc(extent_hooks_t* extent_hooks, void* addr,
102 size_t size, size_t alignment, bool* zero,
103 bool* commit, unsigned arena_ind) {
104 assertx(extent_hooks == &MultiRangeExtentAllocator::s_hooks);
105 if (addr != nullptr) {
106 assertx(false);
107 return nullptr;
109 assert(folly::isPowTwo(alignment));
110 assertx(alignment <= (2u << 20));
112 auto extAlloc = GetByArenaId<MultiRangeExtentAllocator>(arena_ind);
113 for (auto rangeMapper : extAlloc->m_mappers) {
114 if (!rangeMapper) return nullptr;
115 // RangeMapper::addMappingImpl() holds the lock on RangeState when adding
116 // new mappings, so no additional locking is needed here.
117 if (auto addr = rangeMapper->alloc(size, alignment)) {
118 extAlloc->m_allocatedSize.fetch_add(size, std::memory_order_relaxed);
119 return addr;
122 not_reached();
123 return nullptr;
126 extent_hooks_t RangeFallbackExtentAllocator::s_hooks {
127 RangeFallbackExtentAllocator::extent_alloc,
128 nullptr, // dalloc, always fail with opt_retain
129 RangeFallbackExtentAllocator::extent_destroy,
130 RangeFallbackExtentAllocator::extent_commit,
131 nullptr, // decommit, no need with vm_overcommit
132 RangeFallbackExtentAllocator::extent_purge_lazy,
133 RangeFallbackExtentAllocator::extent_purge,
134 extent_split, // always split
135 extent_merge // always merge
139 void* RangeFallbackExtentAllocator::
140 extent_alloc(extent_hooks_t* extent_hooks, void* addr,
141 size_t size, size_t alignment, bool* zero,
142 bool* commit, unsigned arena_ind) {
143 assertx(extent_hooks == &RangeFallbackExtentAllocator::s_hooks);
144 auto extAlloc = GetByArenaId<RangeFallbackExtentAllocator>(arena_ind);
145 auto fallback_hooks = extAlloc->m_fallback_hooks;
146 constexpr size_t kAlign = 2u << 20;
147 if (addr != nullptr || alignment > kAlign) {
148 // Let the default hook handle weird cases.
149 return fallback_hooks->alloc(extent_hooks, addr, size, alignment,
150 zero, commit, arena_ind);
152 if (auto addr = extAlloc->getLowMapper()->alloc(size, alignment)) return addr;
153 return fallback_hooks->alloc(extent_hooks, addr, size, alignment,
154 zero, commit, arena_ind);
157 void RangeFallbackExtentAllocator::
158 extent_destroy(extent_hooks_t* extent_hooks, void* addr, size_t size,
159 bool committed, unsigned arena_ind) {
160 auto extAlloc = GetByArenaId<RangeFallbackExtentAllocator>(arena_ind);
161 if (extAlloc->inRange(addr)) return;
162 auto fallback_hooks = extAlloc->m_fallback_hooks;
163 return fallback_hooks->destroy(extent_hooks, addr, size,
164 committed, arena_ind);
167 bool RangeFallbackExtentAllocator::
168 extent_commit(extent_hooks_t* extent_hooks, void* addr, size_t size,
169 size_t offset, size_t length, unsigned arena_ind) {
170 auto extAlloc = GetByArenaId<RangeFallbackExtentAllocator>(arena_ind);
171 if (extAlloc->inRange(addr)) return false;
172 auto fallback_hooks = extAlloc->m_fallback_hooks;
173 return fallback_hooks->commit(extent_hooks, addr, size,
174 offset, length, arena_ind);
177 bool RangeFallbackExtentAllocator::
178 extent_purge_lazy(extent_hooks_t* extent_hooks, void* addr, size_t size,
179 size_t offset, size_t length, unsigned arena_ind) {
180 auto extAlloc = GetByArenaId<RangeFallbackExtentAllocator>(arena_ind);
181 if (extAlloc->inRange(addr)) return true; // never purge
182 auto fallback_hooks = extAlloc->m_fallback_hooks;
183 auto fallback_purge = fallback_hooks->purge_lazy;
184 if (!fallback_purge) return true;
185 return fallback_purge(extent_hooks, addr, size, offset, length, arena_ind);
188 bool RangeFallbackExtentAllocator::
189 extent_purge(extent_hooks_t* extent_hooks, void* addr, size_t size,
190 size_t offset, size_t length, unsigned arena_ind) {
191 auto extAlloc = GetByArenaId<RangeFallbackExtentAllocator>(arena_ind);
192 if (extAlloc->inRange(addr)) return true; // never purge
193 auto fallback_hooks = extAlloc->m_fallback_hooks;
194 auto fallback_purge = fallback_hooks->purge_forced;
195 if (!fallback_purge) return true;
196 return fallback_purge(extent_hooks, addr, size, offset, length, arena_ind);
201 #endif