aboutsummaryrefslogtreecommitdiffhomepage
path: root/externals/biscuit/src/code_buffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'externals/biscuit/src/code_buffer.cpp')
-rw-r--r--externals/biscuit/src/code_buffer.cpp111
1 files changed, 111 insertions, 0 deletions
diff --git a/externals/biscuit/src/code_buffer.cpp b/externals/biscuit/src/code_buffer.cpp
new file mode 100644
index 00000000..386be375
--- /dev/null
+++ b/externals/biscuit/src/code_buffer.cpp
@@ -0,0 +1,111 @@
+#include <biscuit/assert.hpp>
+#include <biscuit/code_buffer.hpp>
+
+#include <cstring>
+#include <utility>
+
+#ifdef BISCUIT_CODE_BUFFER_MMAP
+#include <sys/mman.h>
+#endif
+
+namespace biscuit {
+
+CodeBuffer::CodeBuffer(size_t capacity)
+ : m_capacity{capacity}, m_is_managed{true} {
+ if (capacity == 0) {
+ return;
+ }
+
+#ifdef BISCUIT_CODE_BUFFER_MMAP
+ m_buffer = static_cast<uint8_t*>(mmap(nullptr, capacity,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0));
+ BISCUIT_ASSERT(m_buffer != nullptr);
+#else
+ m_buffer = new uint8_t[capacity]();
+#endif
+
+ m_cursor = m_buffer;
+}
+
+CodeBuffer::CodeBuffer(uint8_t* buffer, size_t capacity)
+ : m_buffer{buffer}, m_cursor{buffer}, m_capacity{capacity} {
+ BISCUIT_ASSERT(buffer != nullptr);
+}
+
+CodeBuffer::CodeBuffer(CodeBuffer&& other) noexcept
+ : m_buffer{std::exchange(other.m_buffer, nullptr)}
+ , m_cursor{std::exchange(other.m_cursor, nullptr)}
+ , m_capacity{std::exchange(other.m_capacity, size_t{0})}
+ , m_is_managed{std::exchange(other.m_is_managed, false)} {}
+
+CodeBuffer& CodeBuffer::operator=(CodeBuffer&& other) noexcept {
+ if (this == &other) {
+ return *this;
+ }
+
+ std::swap(m_buffer, other.m_buffer);
+ std::swap(m_cursor, other.m_cursor);
+ std::swap(m_capacity, other.m_capacity);
+ std::swap(m_is_managed, other.m_is_managed);
+ return *this;
+}
+
+CodeBuffer::~CodeBuffer() noexcept {
+ if (!m_is_managed) {
+ return;
+ }
+
+#ifdef BISCUIT_CODE_BUFFER_MMAP
+ munmap(m_buffer, m_capacity);
+#else
+ delete[] m_buffer;
+#endif
+}
+
+void CodeBuffer::Grow(size_t new_capacity) {
+ BISCUIT_ASSERT(IsManaged());
+
+ // No-op, just return.
+ if (new_capacity <= m_capacity) {
+ return;
+ }
+
+ const auto cursor_offset = GetCursorOffset();
+
+#ifdef BISCUIT_CODE_BUFFER_MMAP
+ auto* new_buffer = static_cast<uint8_t*>(mremap(m_buffer, m_capacity, new_capacity, MREMAP_MAYMOVE));
+ BISCUIT_ASSERT(new_buffer != nullptr);
+#else
+ auto* new_buffer = new uint8_t[new_capacity]();
+ std::memcpy(new_buffer, m_buffer, m_capacity);
+ delete[] m_buffer;
+#endif
+
+ m_buffer = new_buffer;
+ m_capacity = new_capacity;
+ m_cursor = m_buffer + cursor_offset;
+}
+
+void CodeBuffer::SetExecutable() {
+#ifdef BISCUIT_CODE_BUFFER_MMAP
+ const auto result = mprotect(m_buffer, m_capacity, PROT_READ | PROT_EXEC);
+ BISCUIT_ASSERT(result == 0);
+#else
+ // Unimplemented/Unnecessary for new
+ BISCUIT_ASSERT(false);
+#endif
+}
+
+void CodeBuffer::SetWritable() {
+#ifdef BISCUIT_CODE_BUFFER_MMAP
+ const auto result = mprotect(m_buffer, m_capacity, PROT_READ | PROT_WRITE);
+ BISCUIT_ASSERT(result == 0);
+#else
+ // Unimplemented/Unnecessary for new
+ BISCUIT_ASSERT(false);
+#endif
+}
+
+} // namespace biscuit