enable coroutine for rust emitter
[hiphop-php.git] / hphp / util / read-only-arena.h
blob6d0cd0c9452a8fc067a22b0ffe25d5ec7d0efce0
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 #ifndef incl_HPHP_READ_ONLY_ARENA_H_
17 #define incl_HPHP_READ_ONLY_ARENA_H_
19 #include <mutex>
20 #include <folly/Range.h>
22 namespace HPHP {
24 //////////////////////////////////////////////////////////////////////
27 * ReadOnlyArena is an arena allocator that can be used for arena-lifetime read
28 * only data. In practice this is used in HPHP for process-lifetime cold
29 * runtime data.
31 * When allocating from this arena, you have to provide the data that's
32 * supposed to go in the block.
34 * One read only arena may safely be concurrently accessed by multiple threads.
36 template<typename Alloc>
37 struct ReadOnlyArena {
38 using Allocator = typename Alloc::template rebind<char>::other;
40 * All pointers returned from ReadOnlyArena will have at least this
41 * alignment.
43 static constexpr size_t kMinimalAlignment = 8;
44 static constexpr size_t size4m = 4ull << 20;
47 * Create a ReadOnlyArena that uses at least `minChunkSize' bytes for each
48 * call to the allocator. `minChunkSize' will be rounded up to the nearest
49 * multiple of 4M.
51 explicit ReadOnlyArena(size_t minChunkSize)
52 : m_minChunkSize((minChunkSize + (size4m - 1)) & ~(size4m - 1)) {
54 ReadOnlyArena(const ReadOnlyArena&) = delete;
55 ReadOnlyArena& operator=(const ReadOnlyArena&) = delete;
58 * Destroying a ReadOnlyArena will release all the chunks it allocated, but
59 * generally ReadOnlyArenas should be used for extremely long-lived data.
61 ~ReadOnlyArena() {
62 for (auto& chunk : m_chunks) {
63 m_alloc.deallocate(chunk.data(), chunk.size());
67 size_t capacity() const {
68 return m_cap;
72 * Returns: a pointer to a read only memory region that contains a copy of
73 * [data, data + dataLen).
75 const void* allocate(const void* data, size_t dataLen) {
76 void* ret;
78 // Round up to the minimal alignment.
79 auto alignedLen =
80 (dataLen + (kMinimalAlignment - 1)) & ~(kMinimalAlignment - 1);
81 guard g(m_mutex);
82 ensureFree(alignedLen);
83 assert(((uintptr_t)m_frontier & (kMinimalAlignment - 1)) == 0);
84 assert(m_frontier + alignedLen <= m_end);
85 ret = m_frontier;
86 m_frontier += alignedLen;
88 memcpy(ret, data, dataLen);
89 return ret;
92 private:
93 // Pre: mutex already held, or no other threads may be able to access this.
94 // Post: m_end - m_frontier >= bytes
95 void ensureFree(size_t bytes) {
96 if (m_end - m_frontier >= bytes) return;
98 if (bytes > m_minChunkSize) {
99 bytes = (bytes + (size4m - 1)) & ~(size4m - 1);
100 } else {
101 bytes = m_minChunkSize;
104 m_frontier = m_alloc.allocate(bytes);
105 m_end = m_frontier + bytes;
106 m_chunks.emplace_back(m_frontier, m_end);
107 m_cap += bytes;
110 private:
111 Allocator m_alloc;
112 char* m_frontier{nullptr};
113 char* m_end{nullptr};
114 size_t const m_minChunkSize;
115 size_t m_cap{0};
116 using AR = typename Alloc::template rebind<folly::Range<char*>>::other;
117 std::vector<folly::Range<char*>, AR> m_chunks;
118 mutable std::mutex m_mutex;
119 using guard = std::lock_guard<std::mutex>;
122 //////////////////////////////////////////////////////////////////////
125 #endif