Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion engine/native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ include(Modules)
add_subdirectory(thirdparty SYSTEM)

add_modules_library(core SHARED)
target_link_libraries(core PUBLIC definitions math)
target_link_libraries(core PUBLIC definitions math memory)
1 change: 1 addition & 0 deletions engine/native/core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_modules_library(definitions PIC)
add_modules_library(math)
add_modules_library(memory)
target_link_libraries(math PUBLIC definitions)
1 change: 1 addition & 0 deletions engine/native/core/core.cppm
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export module core;
export import core.defs;
export import core.math;
export import core.memory;
34 changes: 34 additions & 0 deletions engine/native/core/memory/allocator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module;

#include <cstddef>

module core.memory.allocator;

namespace draco::memory
{
Error nilAlloc(
Allocator alloc,
Slice *dst,
size_t size,
size_t align
)
{
return Error::NotImplemented;
}

Error nilFree(Allocator alloc, Slice block)
{
return Error::NotImplemented;
}

Error nilFreeAll(Allocator alloc)
{
return Error::NotImplemented;
}

void asAllocatorVoid(Allocator *dst, void *alloc, AllocatorVTbl *vtbl)
{
dst->allocatorData = (void*)alloc;
dst->vtbl = vtbl;
}
}
55 changes: 55 additions & 0 deletions engine/native/core/memory/allocator.cppm
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module;

#include <cstddef>

export module core.memory.allocator;
export import core.memory.slice;

export namespace draco::memory
{
enum class Error
{
Okay,
OutOfMemory,
NotImplemented,
IllegalAddressRange,
Other, // This one shouldn't be needed. If you see it returned, make a
// new error.
};

struct AllocatorVTbl;

struct Allocator
{
AllocatorVTbl *vtbl;
void *allocatorData;
};

struct AllocatorVTbl
{
using AllocFn = Error (*)(
Allocator alloc,
Slice *dst,
size_t size,
size_t align
);
using FreeFn = Error (*)(Allocator alloc, Slice block);
using FreeAllFn = Error (*)(Allocator alloc);
AllocFn alloc;
FreeFn free;
FreeAllFn freeAll;
};

Error nilAlloc(
Allocator alloc,
Slice *dst,
size_t size,
size_t align
);

Error nilFree(Allocator alloc, Slice block);

Error nilFreeAll(Allocator alloc);

void asAllocatorVoid(Allocator *dst, void *alloc, AllocatorVTbl *vtbl);
}
117 changes: 117 additions & 0 deletions engine/native/core/memory/bumpAllocator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
module;

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
Comment on lines +3 to +7

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify popcount usage and direct header presence in bump allocator implementation.
rg -n --type=cpp 'std::popcount\s*\('
sed -n '1,20p' engine/native/core/memory/bumpAllocator.cpp

Repository: Redot-Engine/DraconicEngine

Length of output: 593


Add missing <bit> header for std::popcount usage.

std::popcount at line 56 requires the <bit> header. Relying on transitive includes is unreliable across different toolchains and compiler configurations.

Suggested fix
 `#include` <algorithm>
+#include <bit>
 `#include` <cassert>
 `#include` <cstddef>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
`#include` <algorithm>
`#include` <bit>
`#include` <cassert>
`#include` <cstddef>
`#include` <cstdint>
`#include` <cstring>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@engine/native/core/memory/bumpAllocator.cpp` around lines 3 - 7, The code
uses std::popcount in bumpAllocator.cpp but doesn’t include the <bit> header;
add the missing include by inserting `#include` <bit> near the other headers so
std::popcount is defined (this affects code around the popcount usage in
bumpAllocator.cpp, e.g., where std::popcount is called).


module core.memory.bumpAllocator;

namespace draco::memory::bump
{
void init(
BumpAllocator *alloc,
Allocator baseAlloc,
// one page by default on unix-like systems
size_t minAllocRequest
)
{
memset(alloc, 0, sizeof(BumpAllocator));
alloc->base = baseAlloc;
alloc->minAllocRequest = minAllocRequest;
}

void deinit(BumpAllocator *alloc)
{
Node *lastNode;
Node *node = alloc->first;
while (node != nullptr)
{
lastNode = node;
node = node->next;
alloc->base.vtbl->free(
alloc->base,
{
.data = (void*)lastNode,
.size = lastNode->size + sizeof(Node),
}
);
}
}

Error alloc(Allocator alloc, Slice *dst, size_t size, size_t align)
{
Error err;
BumpAllocator *allocData = (BumpAllocator *)alloc.allocatorData;
uintptr_t alignMask = align - 1;
Node **lastNode;
Node **node = &(allocData->first);
size_t pos = allocData->allocated;
size_t oldPos = pos;
size_t reqSize = size;
size_t spillover = 0;
Slice newBlock;
uintptr_t currentPtr;
assert(std::popcount(align) == 1);
lastNode = node;
while (((*node) != nullptr) & (pos > 0))
{
oldPos = pos;
pos -= std::min((*node)->size, pos);
lastNode = node;
node = &((*node)->next);
}
assert(pos == 0); // fraudulent mark provided
currentPtr = ((uintptr_t)(*lastNode)) + sizeof(Node) + oldPos;
reqSize = size + ((align - (currentPtr & alignMask)) & alignMask);
if (!(*lastNode) || (reqSize > ((*lastNode)->size - oldPos)))
{
if (*lastNode)
{
spillover = ((*lastNode)->size - oldPos);
}
reqSize = (sizeof(Node) + size + alignMask) & ~alignMask;
err = allocData->base.vtbl->alloc(
allocData->base,
&newBlock,
std::max(allocData->minAllocRequest, reqSize),
std::max(alignof(Node), align)
);
if (err != Error::Okay)
{
return Error::OutOfMemory;
}
(*node) = (Node *)newBlock.data;
(*node)->next = nullptr;
(*node)->size = newBlock.size - sizeof(Node);
pos = 0;
lastNode = node;
oldPos = 0;
}
currentPtr = ((uintptr_t)&((*lastNode)->data[oldPos]));
reqSize = size + ((align - (currentPtr & alignMask)) & alignMask);
currentPtr = (currentPtr + alignMask) & ~alignMask;
allocData->allocated += reqSize + spillover;
Comment thread
VictorSohier marked this conversation as resolved.
dst->data = (void*)currentPtr;
dst->size = size;
return Error::Okay;
}

Error freeAll(Allocator alloc)
{
BumpAllocator *allocData = (BumpAllocator *)alloc.allocatorData;
allocData->allocated = 0;
return Error::Okay;
}

size_t saveMark(BumpAllocator *self)
{
return self->allocated;
}

void resumeMark(BumpAllocator *self, size_t mark)
{
self->allocated = mark;
}
}
59 changes: 59 additions & 0 deletions engine/native/core/memory/bumpAllocator.cppm
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
module;

#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>

export module core.memory.bumpAllocator;
export import core.memory.allocator;
export import core.memory.slice;

export namespace draco::memory
{
namespace bump
{
struct Node
{
Node *next;
size_t size;
uint8_t data[];
};

struct BumpAllocator
{
Allocator base;
Node *first;
size_t minAllocRequest;
size_t allocated;
};

void init(
BumpAllocator *alloc,
Allocator baseAlloc,
// one page by default on unix-like systems
size_t minAllocRequest = (1 << 12)
);

void deinit(BumpAllocator *alloc);

Error alloc(Allocator alloc, Slice *dst, size_t size, size_t align);

Error freeAll(Allocator alloc);

AllocatorVTbl bumpAllocatorVtbl = {
.alloc = alloc,
.free = nilFree,
.freeAll = freeAll,
};

size_t saveMark(BumpAllocator *self);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image


void resumeMark(BumpAllocator *self, size_t mark);

inline void asAllocator(Allocator *dst, BumpAllocator *alloc)
{
asAllocatorVoid(dst, (void*)alloc, &bumpAllocatorVtbl);
}
}
}
Loading