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 #ifndef incl_HPHP_READ_ONLY_ARENA_H_
17 #define incl_HPHP_READ_ONLY_ARENA_H_
20 #include <folly/Range.h>
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
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
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
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.
62 for (auto& chunk
: m_chunks
) {
63 m_alloc
.deallocate(chunk
.data(), chunk
.size());
67 size_t capacity() const {
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
) {
78 // Round up to the minimal alignment.
80 (dataLen
+ (kMinimalAlignment
- 1)) & ~(kMinimalAlignment
- 1);
82 ensureFree(alignedLen
);
83 assert(((uintptr_t)m_frontier
& (kMinimalAlignment
- 1)) == 0);
84 assert(m_frontier
+ alignedLen
<= m_end
);
86 m_frontier
+= alignedLen
;
88 memcpy(ret
, data
, dataLen
);
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);
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
);
112 char* m_frontier
{nullptr};
113 char* m_end
{nullptr};
114 size_t const m_minChunkSize
;
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 //////////////////////////////////////////////////////////////////////