From 5bc921dd2d5ab74f1c8e33f52bdfd9a52dcb5603 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Fri, 29 May 2020 19:36:00 -0500 Subject: [PATCH] [nostalgia/core/gba][ox/std] Move heap manager from NostalgiaCore to OxStd (synced from 98a0c420408f9e6a1ceebbb39376835643dd97db) --- src/ox/std/CMakeLists.txt | 1 + src/ox/std/heapmgr.cpp | 143 +++++++++++++++++++++++++++++++++ src/ox/std/heapmgr.hpp | 33 ++++++++ src/ox/std/std.hpp | 1 + src/ox/std/test/CMakeLists.txt | 1 + src/ox/std/test/tests.cpp | 11 +++ 6 files changed, 190 insertions(+) create mode 100644 src/ox/std/heapmgr.cpp create mode 100644 src/ox/std/heapmgr.hpp diff --git a/src/ox/std/CMakeLists.txt b/src/ox/std/CMakeLists.txt index e327ec7a5..3ca9116d8 100644 --- a/src/ox/std/CMakeLists.txt +++ b/src/ox/std/CMakeLists.txt @@ -3,6 +3,7 @@ add_library( assert.cpp buildinfo.cpp byteswap.cpp + heapmgr.cpp memops.cpp new.cpp random.cpp diff --git a/src/ox/std/heapmgr.cpp b/src/ox/std/heapmgr.cpp new file mode 100644 index 000000000..a7067f38c --- /dev/null +++ b/src/ox/std/heapmgr.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2016 - 2020 gtalent2@gmail.com + * + * 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) { + return sz + (sz & 7); +} + +template +static constexpr std::size_t alignedSize(T = {}) { + return alignedSize(sizeof(T)); +} + +void HeapSegment::init(std::size_t maxSize = ox::bit_cast(g_heapEnd)) { + this->size = maxSize - ox::bit_cast(this); + this->inUse = false; +} + +template +T *HeapSegment::data() { + return ox::bit_cast(ox::bit_cast(this) + alignedSize(this)); +} + +template +T *HeapSegment::end() { + const auto size = alignedSize(this) + alignedSize(this->size); + auto e = ox::bit_cast(ox::bit_cast(this) + size); + return ox::bit_cast(e); +} + + +void initHeap(char *heapBegin, char *heapEnd) { + g_heapBegin = ox::bit_cast(heapBegin); + g_heapEnd = ox::bit_cast(heapEnd); + heapIdx = g_heapBegin; + heapIdx->size = ox::bit_cast(heapEnd) - ox::bit_cast(heapIdx); + heapIdx->inUse = false; +} + +struct SegmentPair { + HeapSegment *anteSegment = nullptr; + HeapSegment *segment = nullptr; +}; + +static SegmentPair findSegmentOf(void *ptr) { + 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) { + 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) { + 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) { + 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) { + return heapmgr::malloc(allocSize); +} + +void *operator new[](std::size_t allocSize) { + return heapmgr::malloc(allocSize); +} + +void operator delete(void *ptr) { + heapmgr::free(ptr); +} + +void operator delete[](void *ptr) { + heapmgr::free(ptr); +} + +void operator delete(void *ptr, unsigned) { + heapmgr::free(ptr); +} + +void operator delete[](void *ptr, unsigned) { + heapmgr::free(ptr); +} + +void operator delete(void *ptr, unsigned long int) { + heapmgr::free(ptr); +} + +void operator delete[](void *ptr, unsigned long int) { + heapmgr::free(ptr); +} + +#endif diff --git a/src/ox/std/heapmgr.hpp b/src/ox/std/heapmgr.hpp new file mode 100644 index 000000000..22876152c --- /dev/null +++ b/src/ox/std/heapmgr.hpp @@ -0,0 +1,33 @@ +/* + * Copyright 2016 - 2020 gtalent2@gmail.com + * + * 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 "types.hpp" + +namespace ox::heapmgr { + +struct HeapSegment { + std::size_t size; + uint8_t inUse; + + void init(std::size_t maxSize); + + template + T *data(); + + template + T *end(); + +}; + +void initHeap(char *heapBegin, char *heapEnd); + +[[nodiscard]] void *malloc(std::size_t allocSize); + +void free(void *ptr); + +} diff --git a/src/ox/std/std.hpp b/src/ox/std/std.hpp index dfc49797a..11b55e043 100644 --- a/src/ox/std/std.hpp +++ b/src/ox/std/std.hpp @@ -15,6 +15,7 @@ #include "error.hpp" #include "hardware.hpp" #include "hashmap.hpp" +#include "heapmgr.hpp" #include "math.hpp" #include "memops.hpp" #include "new.hpp" diff --git a/src/ox/std/test/CMakeLists.txt b/src/ox/std/test/CMakeLists.txt index 81079e32f..b38ded6e1 100644 --- a/src/ox/std/test/CMakeLists.txt +++ b/src/ox/std/test/CMakeLists.txt @@ -15,3 +15,4 @@ add_test("Test\\ BString" StdTest "BString") add_test("Test\\ String" StdTest "String") add_test("Test\\ Vector" StdTest "Vector") add_test("Test\\ HashMap" StdTest "HashMap") +add_test("Test\\ HeapMgr" StdTest malloc) diff --git a/src/ox/std/test/tests.cpp b/src/ox/std/test/tests.cpp index dad605117..f693484ac 100644 --- a/src/ox/std/test/tests.cpp +++ b/src/ox/std/test/tests.cpp @@ -5,6 +5,7 @@ * 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 #include #include @@ -13,6 +14,16 @@ using namespace std; map> tests = { + { + "malloc", + [] { + std::vector buff(ox::units::MB); + ox::heapmgr::initHeap(&buff.front(), &buff.back()); + oxAssert(ox::heapmgr::malloc(5) != nullptr, "malloc is broken"); + oxAssert(ox::heapmgr::malloc(5) != nullptr, "malloc is broken"); + return 0; + } + }, { "ABCDEFG != HIJKLMN", []() {