duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

code_buffer.cpp (2877B)


      1 #include <biscuit/assert.hpp>
      2 #include <biscuit/code_buffer.hpp>
      3 
      4 #include <cstring>
      5 #include <utility>
      6 
      7 #ifdef BISCUIT_CODE_BUFFER_MMAP
      8 #include <sys/mman.h>
      9 #endif
     10 
     11 namespace biscuit {
     12 
     13 CodeBuffer::CodeBuffer(size_t capacity)
     14     : m_capacity{capacity}, m_is_managed{true} {
     15     if (capacity == 0) {
     16         return;
     17     }
     18 
     19 #ifdef BISCUIT_CODE_BUFFER_MMAP
     20     m_buffer = static_cast<uint8_t*>(mmap(nullptr, capacity,
     21                                           PROT_READ | PROT_WRITE,
     22                                           MAP_PRIVATE | MAP_ANONYMOUS,
     23                                           -1, 0));
     24     BISCUIT_ASSERT(m_buffer != nullptr);
     25 #else
     26     m_buffer = new uint8_t[capacity]();
     27 #endif
     28 
     29     m_cursor = m_buffer;
     30 }
     31 
     32 CodeBuffer::CodeBuffer(uint8_t* buffer, size_t capacity)
     33     : m_buffer{buffer}, m_cursor{buffer}, m_capacity{capacity} {
     34     BISCUIT_ASSERT(buffer != nullptr);
     35 }
     36 
     37 CodeBuffer::CodeBuffer(CodeBuffer&& other) noexcept
     38     : m_buffer{std::exchange(other.m_buffer, nullptr)}
     39     , m_cursor{std::exchange(other.m_cursor, nullptr)}
     40     , m_capacity{std::exchange(other.m_capacity, size_t{0})}
     41     , m_is_managed{std::exchange(other.m_is_managed, false)} {}
     42 
     43 CodeBuffer& CodeBuffer::operator=(CodeBuffer&& other) noexcept {
     44     if (this == &other) {
     45         return *this;
     46     }
     47 
     48     std::swap(m_buffer, other.m_buffer);
     49     std::swap(m_cursor, other.m_cursor);
     50     std::swap(m_capacity, other.m_capacity);
     51     std::swap(m_is_managed, other.m_is_managed);
     52     return *this;
     53 }
     54 
     55 CodeBuffer::~CodeBuffer() noexcept {
     56     if (!m_is_managed) {
     57         return;
     58     }
     59 
     60 #ifdef BISCUIT_CODE_BUFFER_MMAP
     61     munmap(m_buffer, m_capacity);
     62 #else
     63     delete[] m_buffer;
     64 #endif
     65 }
     66 
     67 void CodeBuffer::Grow(size_t new_capacity) {
     68     BISCUIT_ASSERT(IsManaged());
     69 
     70     // No-op, just return.
     71     if (new_capacity <= m_capacity) {
     72         return;
     73     }
     74 
     75     const auto cursor_offset = GetCursorOffset();
     76 
     77 #ifdef BISCUIT_CODE_BUFFER_MMAP
     78     auto* new_buffer = static_cast<uint8_t*>(mremap(m_buffer, m_capacity, new_capacity, MREMAP_MAYMOVE));
     79     BISCUIT_ASSERT(new_buffer != nullptr);
     80 #else
     81     auto* new_buffer = new uint8_t[new_capacity]();
     82     std::memcpy(new_buffer, m_buffer, m_capacity);
     83     delete[] m_buffer;
     84 #endif
     85 
     86     m_buffer = new_buffer;
     87     m_capacity = new_capacity;
     88     m_cursor = m_buffer + cursor_offset;
     89 }
     90 
     91 void CodeBuffer::SetExecutable() {
     92 #ifdef BISCUIT_CODE_BUFFER_MMAP
     93     const auto result = mprotect(m_buffer, m_capacity, PROT_READ | PROT_EXEC);
     94     BISCUIT_ASSERT(result == 0);
     95 #else
     96     // Unimplemented/Unnecessary for new
     97     BISCUIT_ASSERT(false);
     98 #endif
     99 }
    100 
    101 void CodeBuffer::SetWritable() {
    102 #ifdef BISCUIT_CODE_BUFFER_MMAP
    103     const auto result = mprotect(m_buffer, m_capacity, PROT_READ | PROT_WRITE);
    104     BISCUIT_ASSERT(result == 0);
    105 #else
    106     // Unimplemented/Unnecessary for new
    107     BISCUIT_ASSERT(false);
    108 #endif
    109 }
    110 
    111 } // namespace biscuit