/* * Copyright 2015 - 2021 gary@drinkingtea.net * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "assert.hpp" #include "bit.hpp" #include "heapmgr.hpp" namespace ox::heapmgr { static struct HeapSegment *volatile g_heapBegin = nullptr; static struct HeapSegment *volatile g_heapEnd = nullptr; static struct HeapSegment *volatile heapIdx = nullptr; static constexpr std::size_t alignedSize(std::size_t sz) noexcept { return sz + (sz & 7); } template static constexpr std::size_t alignedSize(T = {}) noexcept { return alignedSize(sizeof(T)); } void HeapSegment::init(std::size_t maxSize = std::bit_cast(g_heapEnd)) noexcept { this->size = maxSize - std::bit_cast(this); this->inUse = false; } template T *HeapSegment::data() noexcept { return reinterpret_cast(reinterpret_cast(this) + alignedSize(this)); } template T *HeapSegment::end() noexcept { const auto size = alignedSize(this) + alignedSize(this->size); auto e = std::bit_cast(reinterpret_cast(this) + size); return reinterpret_cast(e); } void initHeap(void *heapBegin, void *heapEnd) noexcept { g_heapBegin = reinterpret_cast(heapBegin); g_heapEnd = reinterpret_cast(heapEnd); heapIdx = g_heapBegin; heapIdx->size = std::bit_cast(heapEnd) - std::bit_cast(heapIdx); heapIdx->inUse = false; } struct SegmentPair { HeapSegment *anteSegment = nullptr; HeapSegment *segment = nullptr; }; static SegmentPair findSegmentOf(void *ptr) noexcept { HeapSegment *prev = nullptr; for (auto seg = g_heapBegin; seg < g_heapEnd;) { if (seg->data() == ptr) { return {prev, seg}; } prev = seg; seg = seg->end(); } return {}; } static HeapSegment *findSegmentFor(std::size_t sz) noexcept { for (auto s = g_heapBegin; s <= g_heapEnd; s = s->end()) { if (s->size >= sz && !s->inUse) { return s; } } oxPanic(OxError(1), "malloc: could not find segment"); return nullptr; } [[nodiscard]] void *malloc(std::size_t allocSize) noexcept { const auto targetSize = alignedSize(sizeof(HeapSegment)) + alignedSize(allocSize); auto seg = findSegmentFor(targetSize); if (seg == nullptr) { return nullptr; } const auto bytesRemaining = seg->size - targetSize; seg->size = targetSize; seg->inUse = true; seg->end()->init(bytesRemaining); return seg->data(); } void free(void *ptr) noexcept { auto p = findSegmentOf(ptr); if (p.anteSegment) { p.anteSegment->size += p.segment->size; } else if (p.segment) { p.segment->inUse = false; } else { oxPanic(OxError(1), "Bad heap free"); } } } #ifndef OX_USE_STDLIB using namespace ox; void *operator new(std::size_t allocSize) noexcept { return heapmgr::malloc(allocSize); } void *operator new[](std::size_t allocSize) noexcept { return heapmgr::malloc(allocSize); } void operator delete(void *ptr) noexcept { heapmgr::free(ptr); } void operator delete[](void *ptr) noexcept { heapmgr::free(ptr); } void operator delete(void *ptr, unsigned) noexcept { heapmgr::free(ptr); } void operator delete[](void *ptr, unsigned) noexcept { heapmgr::free(ptr); } void operator delete(void *ptr, unsigned long int) noexcept { heapmgr::free(ptr); } void operator delete[](void *ptr, unsigned long int) noexcept { heapmgr::free(ptr); } #endif