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 #include "hphp/util/read-only-arena.h"
20 #include <folly/Exception.h>
21 #include <folly/portability/SysMman.h>
23 #include "hphp/util/assertions.h"
27 //////////////////////////////////////////////////////////////////////
29 typedef std::lock_guard
<std::mutex
> guard
;
34 * Check return codes on mprotect---we're going to hand memory back to malloc
35 * that we've fiddled with protection on, so if something fails it could cause
36 * issues in completely unrelated parts of the code.
38 void checked_mprotect(void* addr
, size_t size
, int prot
) {
39 auto const rval
= mprotect(addr
, size
, prot
);
40 always_assert_flog(rval
== 0,
41 "mprotect({},{},{})={} failed in ReadOnlyArena",
43 prot
== PROT_READ
? "R" : "RW",
49 //////////////////////////////////////////////////////////////////////
51 ReadOnlyArena::ReadOnlyArena(size_t minChunkSize
)
52 : m_minChunkSize((minChunkSize
+ (s_pageSize
- 1)) & ~(s_pageSize
- 1))
56 always_assert(m_minChunkSize
% s_pageSize
== 0);
59 ReadOnlyArena::~ReadOnlyArena() {
60 for (auto& chunk
: m_chunks
) {
61 checked_mprotect(chunk
.data(), chunk
.size(), PROT_READ
|PROT_WRITE
);
62 std::free(chunk
.data());
66 const void* ReadOnlyArena::allocate(const void* data
, size_t dataLen
) {
69 // Round up to the minimal alignment.
71 (dataLen
+ (kMinimalAlignment
- 1)) & ~(kMinimalAlignment
- 1);
73 ensureFree(alignedLen
);
74 always_assert(m_frontier
+ alignedLen
<= m_end
);
76 auto const ret
= m_frontier
;
77 assert((uintptr_t(ret
) & (kMinimalAlignment
- 1)) == 0);
79 m_frontier
+= alignedLen
;
81 auto pageAddr
= reinterpret_cast<unsigned char*>(
82 uintptr_t(ret
) & ~(s_pageSize
- 1)
84 checked_mprotect(pageAddr
, m_frontier
- pageAddr
, PROT_WRITE
|PROT_READ
);
85 auto const ucData
= static_cast<const unsigned char*>(data
);
86 std::copy(ucData
, ucData
+ dataLen
, ret
);
87 checked_mprotect(pageAddr
, m_frontier
- pageAddr
, PROT_READ
);
92 // Pre: mutex already held, or no other threads may be able to access this
93 // (i.e. it's the ctor).
95 // Post: m_end - m_frontier >= bytes
96 void ReadOnlyArena::ensureFree(size_t bytes
) {
97 if (m_end
- m_frontier
>= bytes
) return;
99 // Allocate a multiple of s_pageSize, and no less than m_minChunkSize.
100 if (bytes
> m_minChunkSize
) {
101 bytes
= (bytes
+ (s_pageSize
- 1)) & ~(s_pageSize
- 1);
103 bytes
= m_minChunkSize
;
107 if (auto err
= posix_memalign(&vp
, s_pageSize
, bytes
)) {
108 folly::throwSystemError(err
, "failed to posix_memalign in "
111 checked_mprotect(vp
, bytes
, PROT_READ
);
113 auto uc
= static_cast<unsigned char*>(vp
);
116 m_chunks
.emplace_back(m_frontier
, m_end
);
119 size_t ReadOnlyArena::capacity() const {
122 for (auto& chunk
: m_chunks
) {
123 size
+= chunk
.size();
128 //////////////////////////////////////////////////////////////////////