diff --git a/kernel/src/Api/Heap.hpp b/kernel/src/Api/Heap.hpp index 5d85e76..a2ec73d 100644 --- a/kernel/src/Api/Heap.hpp +++ b/kernel/src/Api/Heap.hpp @@ -18,7 +18,7 @@ namespace Montauk { uint64_t numPages; }; - static constexpr int MaxHeapAllocs = 128; + static constexpr int MaxHeapAllocs = 512; static HeapAlloc g_heapAllocs[Sched::MaxProcesses][MaxHeapAllocs]; static int g_heapAllocCount[Sched::MaxProcesses]; @@ -43,6 +43,7 @@ namespace Montauk { uint64_t userVa = proc->heapNext; uint64_t numPages = size / 0x1000; + // Allocate physical pages and map them into the process for (uint64_t i = 0; i < numPages; i++) { void* page = Memory::g_pfa->AllocateZeroed(); if (page == nullptr) return 0; @@ -90,7 +91,7 @@ namespace Montauk { uint64_t va = g_heapAllocs[slot][idx].va; uint64_t numPages = g_heapAllocs[slot][idx].numPages; - // Free each physical page and unmap the virtual address + // Free physical pages in bulk and unmap virtual addresses for (uint64_t i = 0; i < numPages; i++) { uint64_t pageVa = va + i * 0x1000; uint64_t physAddr = Memory::VMM::Paging::GetPhysAddr(proc->pml4Phys, pageVa); @@ -100,7 +101,7 @@ namespace Montauk { Memory::VMM::Paging::UnmapUserIn(proc->pml4Phys, pageVa); } - if (slot >= 0) Sched::g_allocatedPages[slot] -= numPages; + Sched::g_allocatedPages[slot] -= numPages; // Remove tracking entry by swapping with the last element g_heapAllocs[slot][idx] = g_heapAllocs[slot][g_heapAllocCount[slot] - 1]; diff --git a/kernel/src/Sched/Scheduler.hpp b/kernel/src/Sched/Scheduler.hpp index 3632b9c..93f9af1 100644 --- a/kernel/src/Sched/Scheduler.hpp +++ b/kernel/src/Sched/Scheduler.hpp @@ -13,7 +13,7 @@ namespace Sched { static constexpr int MaxProcesses = 256; static constexpr uint64_t StackPages = 4; // 16 KiB kernel stack per process static constexpr uint64_t StackSize = StackPages * 0x1000; - static constexpr uint64_t UserStackPages = 4; // 16 KiB user stack + static constexpr uint64_t UserStackPages = 8; // 32 KiB user stack static constexpr uint64_t UserStackSize = UserStackPages * 0x1000; static constexpr uint64_t UserStackTop = 0x7FFFFFF000ULL; // User stack top VA static constexpr uint64_t UserHeapBase = 0x40000000ULL; // User heap start VA diff --git a/programs/include/gui/canvas.hpp b/programs/include/gui/canvas.hpp index 426e8e5..fda9d62 100644 --- a/programs/include/gui/canvas.hpp +++ b/programs/include/gui/canvas.hpp @@ -29,8 +29,18 @@ struct Canvas { void fill(Color c) { uint32_t px = c.to_pixel(); + uint64_t px2 = ((uint64_t)px << 32) | px; int total = w * h; - for (int i = 0; i < total; i++) pixels[i] = px; + int i = 0; + // Align to 8-byte boundary if needed + if (total > 0 && ((uint64_t)pixels & 4)) { + pixels[0] = px; + i = 1; + } + uint64_t* dst64 = (uint64_t*)(pixels + i); + int pairs = (total - i) / 2; + for (int p = 0; p < pairs; p++) dst64[p] = px2; + if ((total - i) & 1) pixels[total - 1] = px; } void put_pixel(int x, int y, Color c) { @@ -40,11 +50,25 @@ struct Canvas { void fill_rect(int x, int y, int rw, int rh, Color c) { uint32_t px = c.to_pixel(); + uint64_t px2 = ((uint64_t)px << 32) | px; int x0 = gui_max(x, 0), y0 = gui_max(y, 0); int x1 = gui_min(x + rw, w), y1 = gui_min(y + rh, h); - for (int dy = y0; dy < y1; dy++) - for (int dx = x0; dx < x1; dx++) - pixels[dy * w + dx] = px; + for (int dy = y0; dy < y1; dy++) { + uint32_t* row = pixels + dy * w; + int dx = x0; + // Align to 8-byte boundary + if (dx < x1 && ((uint64_t)(row + dx) & 4)) { + row[dx] = px; + dx++; + } + // Bulk 2-pixel writes + uint64_t* dst64 = (uint64_t*)(row + dx); + int pairs = (x1 - dx) / 2; + for (int p = 0; p < pairs; p++) dst64[p] = px2; + dx += pairs * 2; + // Remainder + if (dx < x1) row[dx] = px; + } } void fill_rounded_rect(int x, int y, int rw, int rh, int radius, Color c) { @@ -77,8 +101,18 @@ struct Canvas { if (y < 0 || y >= h) return; uint32_t px = c.to_pixel(); int x0 = gui_max(x, 0), x1 = gui_min(x + len, w); - for (int dx = x0; dx < x1; dx++) - pixels[y * w + dx] = px; + uint32_t* row = pixels + y * w; + int dx = x0; + if (dx < x1 && ((uint64_t)(row + dx) & 4)) { + row[dx] = px; + dx++; + } + uint64_t px2 = ((uint64_t)px << 32) | px; + uint64_t* dst64 = (uint64_t*)(row + dx); + int pairs = (x1 - dx) / 2; + for (int p = 0; p < pairs; p++) dst64[p] = px2; + dx += pairs * 2; + if (dx < x1) row[dx] = px; } void vline(int x, int y, int len, Color c) { diff --git a/programs/include/gui/truetype.hpp b/programs/include/gui/truetype.hpp index 26f3e9d..7706763 100644 --- a/programs/include/gui/truetype.hpp +++ b/programs/include/gui/truetype.hpp @@ -136,11 +136,15 @@ struct TrueTypeFont { return gc; } - // Evict oldest cache (slot 0) and shift others down - GlyphCache evicted = caches[0]; + // Evict oldest cache (slot 0) — free its glyph bitmaps + for (int g = 0; g < 256; g++) { + if (caches[0].glyphs[g].bitmap) + montauk::mfree(caches[0].glyphs[g].bitmap); + } + // Shift remaining caches down for (int i = 0; i < 3; i++) - caches[i] = caches[i + 1]; - caches[3] = evicted; + montauk::memcpy(&caches[i], &caches[i + 1], sizeof(GlyphCache)); + montauk::memset(&caches[3], 0, sizeof(GlyphCache)); init_cache(&caches[3], pixel_size); return &caches[3]; } diff --git a/programs/include/montauk/heap.h b/programs/include/montauk/heap.h index 267c2b6..1fa0e72 100644 --- a/programs/include/montauk/heap.h +++ b/programs/include/montauk/heap.h @@ -1,18 +1,18 @@ /* * heap.h * Userspace heap allocator for MontaukOS programs - * Free-list allocator backed by SYS_ALLOC page requests. - * Adapted from the kernel HeapAllocator. - * Copyright (c) 2025 Daniel Hammer + * Copyright (c) 2025 Daniel Hammer */ #pragma once #include +#include namespace montauk { namespace heap_detail { static constexpr uint64_t HEADER_MAGIC = 0x5A484541; // "ZHEA" + static constexpr uint64_t FREED_MAGIC = 0xDEADFEEE; struct Header { uint64_t magic; @@ -24,29 +24,118 @@ namespace heap_detail { FreeNode* next; }; + // Segregated free lists: power-of-2 size classes for blocks <= 4096 bytes. + // Blocks larger than 4096 go to the overflow list. + static constexpr int NUM_BUCKETS = 8; + static constexpr uint64_t BUCKET_SIZES[NUM_BUCKETS] = { + 32, 64, 128, 256, 512, 1024, 2048, 4096 + }; + // Per-process heap state — must be `inline` (not `static`) so that all // translation units in a multi-TU program share a single heap. - inline FreeNode g_head{0, nullptr}; + inline FreeNode* g_buckets[NUM_BUCKETS] = {}; + inline FreeNode g_overflow{0, nullptr}; inline bool g_initialized = false; static inline Header* get_header(void* block) { return (Header*)((uint8_t*)block - sizeof(Header)); } - static inline void insert_free(void* ptr, uint64_t size) { - auto* node = (FreeNode*)ptr; - node->size = size; - node->next = g_head.next; - g_head.next = node; + // Determine which bucket a block size belongs to, or -1 for overflow + static inline int bucket_index(uint64_t blockSize) { + if (blockSize <= 32) return 0; + if (blockSize <= 64) return 1; + if (blockSize <= 128) return 2; + if (blockSize <= 256) return 3; + if (blockSize <= 512) return 4; + if (blockSize <= 1024) return 5; + if (blockSize <= 2048) return 6; + if (blockSize <= 4096) return 7; + return -1; + } + + // Insert into overflow list (sorted by address, with adjacent-block coalescing) + static inline void insert_overflow(void* ptr, uint64_t size) { + auto* node = (FreeNode*)ptr; + node->size = size; + + FreeNode* prev = &g_overflow; + FreeNode* cur = g_overflow.next; + while (cur != nullptr && cur < node) { + prev = cur; + cur = cur->next; + } + + bool merged_prev = false; + if (prev != &g_overflow && + (uint8_t*)prev + prev->size == (uint8_t*)node) { + prev->size += size; + node = prev; + merged_prev = true; + } + + if (cur != nullptr && + (uint8_t*)node + node->size == (uint8_t*)cur) { + node->size += cur->size; + node->next = cur->next; + if (!merged_prev) prev->next = node; + } else if (!merged_prev) { + node->next = cur; + prev->next = node; + } + } + + // Take a block of at least `needed` bytes from the overflow list. + // Splits remainder back into overflow if worthwhile. + static inline void* take_from_overflow(uint64_t needed) { + FreeNode* prev = &g_overflow; + FreeNode* cur = g_overflow.next; + + while (cur != nullptr) { + if (cur->size >= needed) { + uint64_t blockSize = cur->size; + prev->next = cur->next; + + if (blockSize > needed + sizeof(FreeNode) + 16) { + insert_overflow((uint8_t*)cur + needed, blockSize - needed); + } + return (void*)cur; + } + prev = cur; + cur = cur->next; + } + return nullptr; } static inline bool grow(uint64_t bytes) { uint64_t pages = (bytes + 0xFFF) / 0x1000; - if (pages < 4) pages = 4; // grow at least 16 KiB at a time + if (pages < 4) pages = 4; void* mem = montauk::alloc(pages * 0x1000); if (mem == nullptr) return false; - insert_free(mem, pages * 0x1000); + insert_overflow(mem, pages * 0x1000); + return true; + } + + // Refill a small-block bucket by carving a page-sized chunk from overflow + static inline bool refill_bucket(int idx) { + uint64_t bsize = BUCKET_SIZES[idx]; + uint64_t chunk = (bsize < 4096) ? 4096 : bsize; + + void* block = take_from_overflow(chunk); + if (block == nullptr) { + if (!grow(chunk)) return false; + block = take_from_overflow(chunk); + if (block == nullptr) return false; + } + + uint64_t count = chunk / bsize; + for (uint64_t i = 0; i < count; i++) { + auto* node = (FreeNode*)((uint8_t*)block + i * bsize); + node->size = bsize; + node->next = g_buckets[idx]; + g_buckets[idx] = node; + } return true; } @@ -63,41 +152,36 @@ namespace heap_detail { } uint64_t needed = size + sizeof(Header); - needed = (needed + 15) & ~15ULL; // 16-byte alignment + needed = (needed + 15) & ~15ULL; - FreeNode* prev = &g_head; - FreeNode* current = g_head.next; + int idx = bucket_index(needed); - while (current != nullptr) { - if (current->size >= needed) { - uint64_t blockSize = current->size; + if (idx >= 0) { + // Small allocation — use segregated bucket (O(1)) + if (g_buckets[idx] == nullptr && !refill_bucket(idx)) + return nullptr; - // Unlink - prev->next = current->next; + FreeNode* node = g_buckets[idx]; + g_buckets[idx] = node->next; - // Split if worthwhile - if (blockSize > needed + sizeof(FreeNode) + 16) { - void* rest = (void*)((uint8_t*)current + needed); - uint64_t restSize = blockSize - needed; - insert_free(rest, restSize); - } - - // Write allocation header - Header* header = (Header*)current; - header->magic = HEADER_MAGIC; - header->size = size; - - return (void*)((uint8_t*)header + sizeof(Header)); - } - - prev = current; - current = current->next; + Header* header = (Header*)node; + header->magic = HEADER_MAGIC; + header->size = size; + return (void*)((uint8_t*)header + sizeof(Header)); } - // No fit — grow and retry - if (!grow(needed)) - return nullptr; - return malloc(size); + // Large allocation — search overflow list + void* block = take_from_overflow(needed); + if (block == nullptr) { + if (!grow(needed)) return nullptr; + block = take_from_overflow(needed); + if (block == nullptr) return nullptr; + } + + Header* header = (Header*)block; + header->magic = HEADER_MAGIC; + header->size = size; + return (void*)((uint8_t*)header + sizeof(Header)); } inline void mfree(void* ptr) { @@ -107,27 +191,49 @@ namespace heap_detail { Header* header = get_header(ptr); + if (header->magic == FREED_MAGIC) return; // double-free + if (header->magic != HEADER_MAGIC) return; // corrupt + header->magic = FREED_MAGIC; + uint64_t blockSize = header->size + sizeof(Header); blockSize = (blockSize + 15) & ~15ULL; - insert_free((void*)header, blockSize); + int idx = bucket_index(blockSize); + + if (idx >= 0) { + // Small block — push onto bucket (O(1)) + auto* node = (FreeNode*)header; + node->size = BUCKET_SIZES[idx]; + node->next = g_buckets[idx]; + g_buckets[idx] = node; + } else { + // Large block — sorted insert with coalescing + insert_overflow((void*)header, blockSize); + } } inline void* realloc(void* ptr, uint64_t size) { if (ptr == nullptr) return malloc(size); - auto* header = heap_detail::get_header(ptr); - uint64_t old = header->size; + auto* header = heap_detail::get_header(ptr); + uint64_t old = header->size; + + // Compute actual block size (accounting for bucket rounding) + uint64_t oldBlock = (old + sizeof(heap_detail::Header) + 15) & ~15ULL; + int idx = heap_detail::bucket_index(oldBlock); + if (idx >= 0) oldBlock = heap_detail::BUCKET_SIZES[idx]; + + uint64_t newNeed = (size + sizeof(heap_detail::Header) + 15) & ~15ULL; + if (newNeed <= oldBlock) { + header->size = size; + return ptr; + } void* newBlock = malloc(size); if (newBlock == nullptr) return nullptr; - // Copy the smaller of old/new sizes uint64_t copySize = (old < size) ? old : size; - uint8_t* dst = (uint8_t*)newBlock; - uint8_t* src = (uint8_t*)ptr; - for (uint64_t i = 0; i < copySize; i++) - dst[i] = src[i]; + memcpy(newBlock, ptr, copySize); mfree(ptr); return newBlock; diff --git a/programs/include/montauk/string.h b/programs/include/montauk/string.h index a61b240..c85d982 100644 --- a/programs/include/montauk/string.h +++ b/programs/include/montauk/string.h @@ -39,22 +39,58 @@ namespace montauk { inline void memcpy(void* dst, const void* src, uint64_t n) { auto* d = (uint8_t*)dst; auto* s = (const uint8_t*)src; - for (uint64_t i = 0; i < n; i++) d[i] = s[i]; + + // Byte copy until 8-byte aligned + while (n && ((uint64_t)d & 7)) { *d++ = *s++; n--; } + + // Bulk 8-byte copy + auto* d8 = (uint64_t*)d; + auto* s8 = (const uint64_t*)s; + uint64_t words = n / 8; + for (uint64_t i = 0; i < words; i++) d8[i] = s8[i]; + + // Remainder + d = (uint8_t*)(d8 + words); + s = (const uint8_t*)(s8 + words); + for (uint64_t i = 0; i < (n & 7); i++) d[i] = s[i]; } inline void memmove(void* dst, const void* src, uint64_t n) { auto* d = (uint8_t*)dst; auto* s = (const uint8_t*)src; - if (d < s) { - for (uint64_t i = 0; i < n; i++) d[i] = s[i]; + if (d < s || d >= s + n) { + memcpy(dst, src, n); } else { - for (uint64_t i = n; i > 0; i--) d[i-1] = s[i-1]; + // Backward copy — bulk 8 bytes at a time from end + d += n; s += n; + while (n && ((uint64_t)d & 7)) { *--d = *--s; n--; } + auto* d8 = (uint64_t*)d; + auto* s8 = (const uint64_t*)s; + uint64_t words = n / 8; + for (uint64_t i = 1; i <= words; i++) d8[-i] = s8[-i]; + d = (uint8_t*)(d8 - words); + s = (const uint8_t*)(s8 - words); + for (uint64_t i = 1; i <= (n & 7); i++) d[-i] = s[-i]; } } inline void memset(void* dst, int val, uint64_t n) { auto* d = (uint8_t*)dst; - for (uint64_t i = 0; i < n; i++) d[i] = (uint8_t)val; + uint8_t v = (uint8_t)val; + + // Byte fill until 8-byte aligned + while (n && ((uint64_t)d & 7)) { *d++ = v; n--; } + + // Bulk 8-byte fill + uint64_t v8 = v; + v8 |= v8 << 8; v8 |= v8 << 16; v8 |= v8 << 32; + auto* d8 = (uint64_t*)d; + uint64_t words = n / 8; + for (uint64_t i = 0; i < words; i++) d8[i] = v8; + + // Remainder + d = (uint8_t*)(d8 + words); + for (uint64_t i = 0; i < (n & 7); i++) d[i] = v; } inline void strcpy(char* dst, const char* src) { diff --git a/programs/lib/libc/libc.c b/programs/lib/libc/libc.c index 5475c9b..c57f1e8 100644 --- a/programs/lib/libc/libc.c +++ b/programs/lib/libc/libc.c @@ -66,27 +66,61 @@ int errno = 0; void *memcpy(void *dest, const void *src, size_t n) { unsigned char *d = (unsigned char *)dest; const unsigned char *s = (const unsigned char *)src; - for (size_t i = 0; i < n; i++) - d[i] = s[i]; + + /* Byte copy until 8-byte aligned */ + while (n && ((uint64_t)d & 7)) { *d++ = *s++; n--; } + + /* Bulk 8-byte copy */ + uint64_t *d8 = (uint64_t *)d; + const uint64_t *s8 = (const uint64_t *)s; + size_t words = n / 8; + for (size_t i = 0; i < words; i++) d8[i] = s8[i]; + + /* Remainder */ + d = (unsigned char *)(d8 + words); + s = (const unsigned char *)(s8 + words); + for (size_t i = 0; i < (n & 7); i++) d[i] = s[i]; + return dest; } void *memset(void *s, int c, size_t n) { unsigned char *p = (unsigned char *)s; - for (size_t i = 0; i < n; i++) - p[i] = (unsigned char)c; + unsigned char v = (unsigned char)c; + + /* Byte fill until 8-byte aligned */ + while (n && ((uint64_t)p & 7)) { *p++ = v; n--; } + + /* Bulk 8-byte fill */ + uint64_t v8 = v; + v8 |= v8 << 8; v8 |= v8 << 16; v8 |= v8 << 32; + uint64_t *p8 = (uint64_t *)p; + size_t words = n / 8; + for (size_t i = 0; i < words; i++) p8[i] = v8; + + /* Remainder */ + p = (unsigned char *)(p8 + words); + for (size_t i = 0; i < (n & 7); i++) p[i] = v; + return s; } void *memmove(void *dest, const void *src, size_t n) { unsigned char *d = (unsigned char *)dest; const unsigned char *s = (const unsigned char *)src; - if (s < d && d < s + n) { - for (size_t i = n; i > 0; i--) - d[i - 1] = s[i - 1]; + if (d < s || d >= s + n) { + memcpy(dest, src, n); } else { - for (size_t i = 0; i < n; i++) - d[i] = s[i]; + /* Backward copy — bulk 8 bytes at a time from end */ + d += n; s += n; + while (n && ((uint64_t)d & 7)) { *--d = *--s; n--; } + uint64_t *d8 = (uint64_t *)d; + const uint64_t *s8 = (const uint64_t *)s; + size_t words = n / 8; + for (size_t i = 1; i <= words; i++) d8[-(long)i] = s8[-(long)i]; + d = (unsigned char *)(d8 - words); + s = (const unsigned char *)(s8 - words); + for (size_t i = 1; i <= (n & 7); i++) d[-(long)i] = s[-(long)i]; } return dest; } @@ -228,7 +262,8 @@ int tolower(int c) { return (c >= 'A' && c <= 'Z') ? c + 32 : c; } Heap allocator (free-list, backed by SYS_ALLOC) ======================================================================== */ -#define HEAP_MAGIC 0x5A484541ULL /* "ZHEA" */ +#define HEAP_MAGIC 0x5A484541ULL /* "ZHEA" */ +#define FREED_MAGIC 0xDEADFEEEULL struct HeapHeader { uint64_t magic; @@ -240,14 +275,78 @@ struct FreeNode { struct FreeNode *next; }; -static struct FreeNode g_heapHead = { 0, NULL }; +/* Segregated free lists: power-of-2 size classes for blocks <= 4096 bytes */ +#define NUM_BUCKETS 8 +static const uint64_t BUCKET_SIZES[NUM_BUCKETS] = { + 32, 64, 128, 256, 512, 1024, 2048, 4096 +}; + +static struct FreeNode *g_buckets[NUM_BUCKETS] = {}; +static struct FreeNode g_overflow = { 0, NULL }; static int g_heapInit = 0; -static void heap_insert_free(void *ptr, uint64_t size) { +static int heap_bucket_index(uint64_t blockSize) { + if (blockSize <= 32) return 0; + if (blockSize <= 64) return 1; + if (blockSize <= 128) return 2; + if (blockSize <= 256) return 3; + if (blockSize <= 512) return 4; + if (blockSize <= 1024) return 5; + if (blockSize <= 2048) return 6; + if (blockSize <= 4096) return 7; + return -1; +} + +/* Insert into overflow list (sorted by address, with coalescing) */ +static void heap_insert_overflow(void *ptr, uint64_t size) { struct FreeNode *node = (struct FreeNode *)ptr; node->size = size; - node->next = g_heapHead.next; - g_heapHead.next = node; + + struct FreeNode *prev = &g_overflow; + struct FreeNode *cur = g_overflow.next; + while (cur != NULL && cur < node) { + prev = cur; + cur = cur->next; + } + + int merged_prev = 0; + if (prev != &g_overflow && + (uint8_t *)prev + prev->size == (uint8_t *)node) { + prev->size += size; + node = prev; + merged_prev = 1; + } + + if (cur != NULL && + (uint8_t *)node + node->size == (uint8_t *)cur) { + node->size += cur->size; + node->next = cur->next; + if (!merged_prev) prev->next = node; + } else if (!merged_prev) { + node->next = cur; + prev->next = node; + } +} + +/* Take a block >= needed from overflow. Splits remainder back. */ +static void *heap_take_overflow(uint64_t needed) { + struct FreeNode *prev = &g_overflow; + struct FreeNode *cur = g_overflow.next; + + while (cur != NULL) { + if (cur->size >= needed) { + uint64_t blockSize = cur->size; + prev->next = cur->next; + + if (blockSize > needed + sizeof(struct FreeNode) + 16) { + heap_insert_overflow((uint8_t *)cur + needed, blockSize - needed); + } + return (void *)cur; + } + prev = cur; + cur = cur->next; + } + return NULL; } static void heap_grow(uint64_t bytes) { @@ -255,7 +354,29 @@ static void heap_grow(uint64_t bytes) { if (pages < 4) pages = 4; void *mem = (void *)_zos_syscall1(SYS_ALLOC, (long)(pages * 0x1000)); if (mem != NULL) - heap_insert_free(mem, pages * 0x1000); + heap_insert_overflow(mem, pages * 0x1000); +} + +/* Refill a small-block bucket from overflow */ +static int heap_refill_bucket(int idx) { + uint64_t bsize = BUCKET_SIZES[idx]; + uint64_t chunk = (bsize < 4096) ? 4096 : bsize; + + void *block = heap_take_overflow(chunk); + if (block == NULL) { + heap_grow(chunk); + block = heap_take_overflow(chunk); + if (block == NULL) return 0; + } + + uint64_t count = chunk / bsize; + for (uint64_t i = 0; i < count; i++) { + struct FreeNode *node = (struct FreeNode *)((uint8_t *)block + i * bsize); + node->size = bsize; + node->next = g_buckets[idx]; + g_buckets[idx] = node; + } + return 1; } void *malloc(size_t size) { @@ -267,39 +388,60 @@ void *malloc(size_t size) { uint64_t needed = size + sizeof(struct HeapHeader); needed = (needed + 15) & ~15ULL; - struct FreeNode *prev = &g_heapHead; - struct FreeNode *cur = g_heapHead.next; + int idx = heap_bucket_index(needed); - while (cur != NULL) { - if (cur->size >= needed) { - uint64_t blockSize = cur->size; - prev->next = cur->next; + if (idx >= 0) { + /* Small allocation — use segregated bucket (O(1)) */ + if (g_buckets[idx] == NULL && !heap_refill_bucket(idx)) + return NULL; - if (blockSize > needed + sizeof(struct FreeNode) + 16) { - void *rest = (void *)((uint8_t *)cur + needed); - heap_insert_free(rest, blockSize - needed); - } + struct FreeNode *node = g_buckets[idx]; + g_buckets[idx] = node->next; - struct HeapHeader *hdr = (struct HeapHeader *)cur; - hdr->magic = HEAP_MAGIC; - hdr->size = size; - return (void *)((uint8_t *)hdr + sizeof(struct HeapHeader)); - } - prev = cur; - cur = cur->next; + struct HeapHeader *hdr = (struct HeapHeader *)node; + hdr->magic = HEAP_MAGIC; + hdr->size = size; + return (void *)((uint8_t *)hdr + sizeof(struct HeapHeader)); } - heap_grow(needed); - return malloc(size); + /* Large allocation — search overflow list */ + void *block = heap_take_overflow(needed); + if (block == NULL) { + heap_grow(needed); + block = heap_take_overflow(needed); + if (block == NULL) return NULL; + } + + struct HeapHeader *hdr = (struct HeapHeader *)block; + hdr->magic = HEAP_MAGIC; + hdr->size = size; + return (void *)((uint8_t *)hdr + sizeof(struct HeapHeader)); } void free(void *ptr) { if (ptr == NULL) return; struct HeapHeader *hdr = (struct HeapHeader *)((uint8_t *)ptr - sizeof(struct HeapHeader)); + + if (hdr->magic == FREED_MAGIC) return; /* double-free */ + if (hdr->magic != HEAP_MAGIC) return; /* corrupt */ + hdr->magic = FREED_MAGIC; + uint64_t blockSize = hdr->size + sizeof(struct HeapHeader); blockSize = (blockSize + 15) & ~15ULL; - heap_insert_free((void *)hdr, blockSize); + + int idx = heap_bucket_index(blockSize); + + if (idx >= 0) { + /* Small block — push onto bucket (O(1)) */ + struct FreeNode *node = (struct FreeNode *)hdr; + node->size = BUCKET_SIZES[idx]; + node->next = g_buckets[idx]; + g_buckets[idx] = node; + } else { + /* Large block — sorted insert with coalescing */ + heap_insert_overflow((void *)hdr, blockSize); + } } void *calloc(size_t nmemb, size_t size) { @@ -316,6 +458,17 @@ void *realloc(void *ptr, size_t size) { struct HeapHeader *hdr = (struct HeapHeader *)((uint8_t *)ptr - sizeof(struct HeapHeader)); uint64_t old = hdr->size; + /* Compute actual block size (accounting for bucket rounding) */ + uint64_t oldBlock = (old + sizeof(struct HeapHeader) + 15) & ~15ULL; + int idx = heap_bucket_index(oldBlock); + if (idx >= 0) oldBlock = BUCKET_SIZES[idx]; + + uint64_t newNeed = (size + sizeof(struct HeapHeader) + 15) & ~15ULL; + if (newNeed <= oldBlock) { + hdr->size = size; + return ptr; + } + void *newp = malloc(size); if (newp == NULL) return NULL; diff --git a/programs/lib/libc/obj/libc.o b/programs/lib/libc/obj/libc.o index 961fbdf..b8aef84 100644 Binary files a/programs/lib/libc/obj/libc.o and b/programs/lib/libc/obj/libc.o differ diff --git a/programs/lib/libjpeg/libjpeg.a b/programs/lib/libjpeg/libjpeg.a index 97a9d79..9d9d5aa 100644 Binary files a/programs/lib/libjpeg/libjpeg.a and b/programs/lib/libjpeg/libjpeg.a differ diff --git a/programs/lib/tls/libtls.a b/programs/lib/tls/libtls.a index d9600c4..5e03410 100644 Binary files a/programs/lib/tls/libtls.a and b/programs/lib/tls/libtls.a differ diff --git a/programs/lib/tls/obj/tls.o b/programs/lib/tls/obj/tls.o index ec70240..8cd7af3 100644 Binary files a/programs/lib/tls/obj/tls.o and b/programs/lib/tls/obj/tls.o differ diff --git a/programs/src/desktop/main.cpp b/programs/src/desktop/main.cpp index 221f867..88f6eed 100644 --- a/programs/src/desktop/main.cpp +++ b/programs/src/desktop/main.cpp @@ -82,7 +82,7 @@ void gui::desktop_init(DesktopState* ds) { ds->settings.ui_scale = 1; // Try to load default wallpaper - wallpaper_load(&ds->settings, "0:/home/stephen-walker-DaC8D3USffk-unsplash.jpg", + wallpaper_load(&ds->settings, "0:/home/kristaps-ungurs-llezNN2OGEY-unsplash.jpg", ds->screen_w, ds->screen_h); montauk::win_setscale(1); diff --git a/programs/src/fontpreview/Makefile b/programs/src/fontpreview/Makefile index 94d20bb..600828a 100644 --- a/programs/src/fontpreview/Makefile +++ b/programs/src/fontpreview/Makefile @@ -15,6 +15,7 @@ endif # ---- Paths ---- +LIBC_LIB := ../../lib/libc PROG_INC := ../../include LINK_LD := ../../link.ld BINDIR := ../../bin @@ -59,6 +60,10 @@ LDFLAGS := \ -z max-page-size=0x1000 \ -T $(LINK_LD) +# ---- Libraries ---- + +LIBS := $(LIBC_LIB)/liblibc.a + # ---- Source files ---- SRCS := main.cpp stb_truetype_impl.cpp @@ -72,9 +77,9 @@ TARGET := $(BINDIR)/os/fontpreview.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile +$(TARGET): $(OBJS) $(LIBS) $(LINK_LD) Makefile mkdir -p $(BINDIR)/os - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/imageviewer/main.cpp b/programs/src/imageviewer/main.cpp index 9741a49..6fd023a 100644 --- a/programs/src/imageviewer/main.cpp +++ b/programs/src/imageviewer/main.cpp @@ -1,7 +1,6 @@ /* * main.cpp - * MontaukOS Image Viewer - standalone Window Server process - * Displays images with zoom, pan, fit-to-window, and 1:1 modes + * MontaukOS Image Viewer * Copyright (c) 2026 Daniel Hammer */