feng-arch 2c4811cea4
Some checks failed
JavaScript code lint and formatting with Biome / eslint (push) Has been cancelled
Check code formatting / code-formatting (push) Has been cancelled
Check code size / build (push) Has been cancelled
Check spelling with codespell / codespell (push) Has been cancelled
Check commit message formatting / build (push) Has been cancelled
Build docs / build (push) Has been cancelled
Check examples / embedding (push) Has been cancelled
Package mpremote / build (push) Has been cancelled
.mpy file format and tools / test (push) Has been cancelled
Build ports metadata / build (push) Has been cancelled
cc3200 port / build (push) Has been cancelled
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Has been cancelled
esp32 port / build_idf (esp32_build_s3_c3) (push) Has been cancelled
esp8266 port / build (push) Has been cancelled
mimxrt port / build (push) Has been cancelled
nrf port / build (push) Has been cancelled
powerpc port / build (push) Has been cancelled
qemu port / build_and_test_arm (push) Has been cancelled
qemu port / build_and_test_rv32 (push) Has been cancelled
renesas-ra port / build_renesas_ra_board (push) Has been cancelled
rp2 port / build (push) Has been cancelled
samd port / build (push) Has been cancelled
stm32 port / build_stm32 (stm32_misc_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_nucleo_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_pyb_build) (push) Has been cancelled
unix port / minimal (push) Has been cancelled
unix port / reproducible (push) Has been cancelled
unix port / standard (push) Has been cancelled
unix port / standard_v2 (push) Has been cancelled
unix port / coverage (push) Has been cancelled
unix port / coverage_32bit (push) Has been cancelled
unix port / nanbox (push) Has been cancelled
unix port / float (push) Has been cancelled
unix port / stackless_clang (push) Has been cancelled
unix port / float_clang (push) Has been cancelled
unix port / settrace (push) Has been cancelled
unix port / settrace_stackless (push) Has been cancelled
unix port / macos (push) Has been cancelled
unix port / qemu_mips (push) Has been cancelled
unix port / qemu_arm (push) Has been cancelled
unix port / qemu_riscv64 (push) Has been cancelled
webassembly port / build (push) Has been cancelled
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, dev) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, standard) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, dev) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, standard) (push) Has been cancelled
windows port / cross-build-on-linux (push) Has been cancelled
zephyr port / build (push) Has been cancelled
rp2 port / build (PICO) (push) Has been cancelled
Python code lint and formatting with ruff / ruff (push) Has been cancelled
stm32 port / build (STM32F7DISC) (push) Has been cancelled
unix port / build (push) Has been cancelled
JavaScript code lint and formatting with Biome / eslint (pull_request) Has been cancelled
Check code formatting / code-formatting (pull_request) Has been cancelled
Check code size / build (pull_request) Has been cancelled
Check spelling with codespell / codespell (pull_request) Has been cancelled
Check commit message formatting / build (pull_request) Has been cancelled
Build ports metadata / build (pull_request) Has been cancelled
cc3200 port / build (pull_request) Has been cancelled
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (pull_request) Has been cancelled
esp32 port / build_idf (esp32_build_s3_c3) (pull_request) Has been cancelled
esp8266 port / build (pull_request) Has been cancelled
mimxrt port / build (pull_request) Has been cancelled
nrf port / build (pull_request) Has been cancelled
powerpc port / build (pull_request) Has been cancelled
qemu port / build_and_test_arm (pull_request) Has been cancelled
qemu port / build_and_test_rv32 (pull_request) Has been cancelled
renesas-ra port / build_renesas_ra_board (pull_request) Has been cancelled
rp2 port / build (pull_request) Has been cancelled
samd port / build (pull_request) Has been cancelled
stm32 port / build_stm32 (stm32_misc_build) (pull_request) Has been cancelled
stm32 port / build_stm32 (stm32_nucleo_build) (pull_request) Has been cancelled
stm32 port / build_stm32 (stm32_pyb_build) (pull_request) Has been cancelled
unix port / minimal (pull_request) Has been cancelled
unix port / reproducible (pull_request) Has been cancelled
unix port / standard (pull_request) Has been cancelled
unix port / standard_v2 (pull_request) Has been cancelled
unix port / coverage (pull_request) Has been cancelled
unix port / coverage_32bit (pull_request) Has been cancelled
unix port / nanbox (pull_request) Has been cancelled
unix port / float (pull_request) Has been cancelled
unix port / stackless_clang (pull_request) Has been cancelled
unix port / float_clang (pull_request) Has been cancelled
unix port / settrace (pull_request) Has been cancelled
unix port / settrace_stackless (pull_request) Has been cancelled
unix port / macos (pull_request) Has been cancelled
unix port / qemu_mips (pull_request) Has been cancelled
unix port / qemu_arm (pull_request) Has been cancelled
unix port / qemu_riscv64 (pull_request) Has been cancelled
webassembly port / build (pull_request) Has been cancelled
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-mingw (i686, mingw32, dev) (pull_request) Has been cancelled
windows port / build-mingw (i686, mingw32, standard) (pull_request) Has been cancelled
windows port / build-mingw (x86_64, mingw64, dev) (pull_request) Has been cancelled
windows port / build-mingw (x86_64, mingw64, standard) (pull_request) Has been cancelled
windows port / cross-build-on-linux (pull_request) Has been cancelled
zephyr port / build (pull_request) Has been cancelled
rp2 port / build (PICO) (pull_request) Has been cancelled
Python code lint and formatting with ruff / ruff (pull_request) Has been cancelled
stm32 port / build (STM32F7DISC) (pull_request) Has been cancelled
unix port / build (pull_request) Has been cancelled
feat: add support for eigenmath
2025-10-13 15:42:15 +08:00

341 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*========================================================================
* eheap.c Improved standalone heap manager
* 32-bit, aligned, safe operations
*======================================================================*/
#include "eheap.h"
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "py/runtime.h"
#ifndef EHEAP_ALIGN
#define EHEAP_ALIGN 4 /* default byte alignment (power of two) */
#endif
#define ALIGN_MASK (EHEAP_ALIGN - 1)
#define ALIGN_UP(x) (((x) + ALIGN_MASK) & ~ALIGN_MASK)
/*-------------------------------------------------- block header layout */
typedef struct block_link {
struct block_link *next;
size_t size; /* MSB=1 => allocated, lower bits => block size */
} block_t;
#define USED_MASK ((size_t)1 << (sizeof(size_t)*8 - 1))
#define IS_USED(b) (((b)->size) & USED_MASK)
#define MARK_USED(b) ((b)->size |= USED_MASK)
#define MARK_FREE(b) ((b)->size &= ~USED_MASK)
#define BLOCK_SIZE(b) ((b)->size & ~USED_MASK)
#define HDR_SIZE ALIGN_UP(sizeof(block_t))
#define MIN_SPLIT (HDR_SIZE * 2)
/*-------------------------------------------------- heap globals */
static uint8_t *heap_base = NULL;
static uint8_t *heap_end = NULL;
static size_t heap_total = 0;
static block_t start_node; /* dummy head */
static block_t end_marker; /* tail sentinel storage */
static block_t *end_node = &end_marker;
static size_t free_bytes = 0;
static size_t min_free = 0;
static bool initialized = false;
/*-------------------------------------------------------------------*/
static bool is_valid_block(block_t *blk) {
uint8_t *ptr = (uint8_t*)blk;
if (ptr < heap_base || ptr >= heap_end) return false;
return (((uintptr_t)ptr - (uintptr_t)heap_base) & ALIGN_MASK) == 0;
}
/* Insert and coalesce a free block (address-ordered), with overflow guards */
static void insert_free(block_t *blk) {
if (!is_valid_block(blk) || IS_USED(blk)) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insert_free: invalid or used block"));
return;
}
size_t blk_sz = BLOCK_SIZE(blk);
/* guard pointer addition overflow */
if (blk_sz > (size_t)(heap_end - (uint8_t*)blk)) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insert_free: block size overflow"));
return;
}
uint8_t *blk_end = (uint8_t*)blk + blk_sz;
block_t *prev = &start_node;
/* find insertion point */
while (prev->next < blk && prev->next != end_node) {
prev = prev->next;
if (!is_valid_block(prev)) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insert_free: corrupted free list"));
return;
}
}
/* forward merge */
if (prev->next != end_node) {
block_t *fwd = prev->next;
if (!IS_USED(fwd) &&
(uint8_t*)fwd == blk_end) {
/* fuse sizes */
size_t total = blk_sz + BLOCK_SIZE(fwd);
if (total < blk_sz) { /* overflow? */
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insert_free: combine overflow"));
return;
}
blk->size = total;
blk->next = fwd->next;
blk_sz = total; /* update for potential backward merge */
} else {
blk->next = fwd;
}
} else {
blk->next = end_node;
}
/* backward merge */
if (prev != &start_node && !IS_USED(prev)) {
uint8_t *prev_end = (uint8_t*)prev + BLOCK_SIZE(prev);
if (prev_end == (uint8_t*)blk) {
size_t total = BLOCK_SIZE(prev) + blk_sz;
if (total < BLOCK_SIZE(prev)) { /* overflow? */
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insert_free: combine overflow"));
return;
}
prev->size = total;
prev->next = blk->next;
return;
}
}
prev->next = blk;
}
static void heap_init_once(void) {
if (initialized) return;
/* single free block covers [heap_base .. heap_end) excluding end_node */
block_t *first = (block_t*)heap_base;
first->size = (heap_total - HDR_SIZE);
MARK_FREE(first);
first->next = end_node;
start_node.next = first;
start_node.size = 0;
/* initialize end marker */
end_node->next = NULL;
end_node->size = 0;
MARK_USED(end_node);
free_bytes = BLOCK_SIZE(first);
min_free = free_bytes;
initialized = true;
}
void eheap_init(void *buf, size_t bytes) {
if (!buf || bytes <= HDR_SIZE*2 + ALIGN_MASK) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("eheap_init: invalid region"));
return;
}
/* align base upward */
uintptr_t start = ALIGN_UP((uintptr_t)buf);
size_t loss = start - (uintptr_t)buf;
bytes = (bytes > loss) ? bytes - loss : 0;
bytes = (bytes / EHEAP_ALIGN) * EHEAP_ALIGN;
if (bytes <= HDR_SIZE*2) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("eheap_init: too small after align"));
return;
}
heap_base = (uint8_t*)start;
heap_total = bytes;
/* reserve tail for end_node */
size_t res = ALIGN_UP(sizeof(block_t));
heap_total -= res;
end_node = (block_t*)(heap_base + heap_total);
heap_end = heap_base + heap_total;
initialized = false;
heap_init_once();
}
void* e_malloc(size_t size) {
if (size == 0 || !initialized) return NULL;
/* check overflow */
if (size > SIZE_MAX - HDR_SIZE) return NULL;
size_t needed = ALIGN_UP(size + HDR_SIZE);
block_t *prev = &start_node;
block_t *cur = start_node.next;
while (cur != end_node) {
if (!is_valid_block(cur)) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_malloc: corrupted heap"));
return NULL;
}
if (!IS_USED(cur) && BLOCK_SIZE(cur) >= needed) {
size_t remain = BLOCK_SIZE(cur) - needed;
if (remain >= MIN_SPLIT) {
/* split */
block_t *split = (block_t*)((uint8_t*)cur + needed);
split->size = remain;
MARK_FREE(split);
split->next = cur->next;
cur->size = needed;
prev->next = split;
} else {
/* use entire */
prev->next = cur->next;
needed = BLOCK_SIZE(cur);
}
MARK_USED(cur);
free_bytes -= needed;
if (free_bytes < min_free) min_free = free_bytes;
return (uint8_t*)cur + HDR_SIZE;
}
prev = cur;
cur = cur->next;
}
return NULL;
}
void e_free(void *ptr) {
if (!ptr || !initialized) return;
uint8_t *p = (uint8_t*)ptr;
if (p < heap_base + HDR_SIZE || p >= heap_end) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_free: invalid ptr"));
return;
}
if (((uintptr_t)p - HDR_SIZE) & ALIGN_MASK) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_free: unaligned ptr"));
return;
}
block_t *blk = (block_t*)(p - HDR_SIZE);
if (!IS_USED(blk)) {
//mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_free: double free"));
return;
}
size_t sz = BLOCK_SIZE(blk);
if (sz == 0 || (uint8_t*)blk + sz > heap_end) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_free: bad size"));
return;
}
MARK_FREE(blk);
free_bytes += sz;
insert_free(blk);
}
void* e_realloc(void *ptr, size_t new_size) {
if (!ptr) return e_malloc(new_size);
if (new_size == 0) { e_free(ptr); return NULL; }
if (!initialized) return NULL;
uint8_t *p = (uint8_t*)ptr;
if (p < heap_base + HDR_SIZE || p >= heap_end) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_realloc: invalid ptr"));
return NULL;
}
block_t *blk = (block_t*)(p - HDR_SIZE);
if (!IS_USED(blk)) {
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_realloc: block not used"));
return NULL;
}
size_t curr = BLOCK_SIZE(blk) - HDR_SIZE;
if (new_size <= curr) return ptr;
/* try expand into next free block */
uint8_t *next_addr = (uint8_t*)blk + BLOCK_SIZE(blk);
if (next_addr + HDR_SIZE <= heap_end) {
block_t *next = (block_t*)next_addr;
if (is_valid_block(next) && !IS_USED(next)) {
size_t combined = BLOCK_SIZE(blk) + BLOCK_SIZE(next);
size_t need = ALIGN_UP(new_size + HDR_SIZE);
if (combined >= need) {
/* remove next from free list */
block_t *prev = &start_node;
while (prev->next != next && prev->next != end_node) {
prev = prev->next;
}
if (prev->next == next) {
prev->next = next->next;
/* compute new free_bytes: remove next size */
free_bytes -= BLOCK_SIZE(next);
/* update blk size */
blk->size = (blk->size & USED_MASK) | need;
size_t leftover = combined - need;
if (leftover >= MIN_SPLIT) {
block_t *split = (block_t*)((uint8_t*)blk + need);
split->size = leftover;
MARK_FREE(split);
insert_free(split);
} else {
/* absorb all */
blk->size = (blk->size & USED_MASK) | combined;
}
if (free_bytes < min_free) min_free = free_bytes;
return ptr;
}
}
}
}
/* fallback: alloc-copy-free */
void *nptr = e_malloc(new_size);
if (nptr) {
memcpy(nptr, ptr, curr);
e_free(ptr);
}
return nptr;
}
size_t e_heap_free(void) { return free_bytes; }
size_t e_heap_min_free(void) { return min_free; }
int e_heap_fragmentation(void) {
if (!initialized || free_bytes == 0) return 0;
size_t largest = 0;
for (block_t *b = start_node.next; b != end_node; b = b->next) {
if (!IS_USED(b) && BLOCK_SIZE(b) > largest) {
largest = BLOCK_SIZE(b);
}
}
if (largest == 0) return 100;
return (int)(100 - (largest * 100) / free_bytes);
}
bool e_heap_validate(void) {
if (!initialized) return false;
size_t counted = 0;
for (block_t *b = start_node.next; b != end_node; b = b->next) {
if (!is_valid_block(b)) return false;
if ((uint8_t*)b + BLOCK_SIZE(b) > heap_end) return false;
if (!IS_USED(b)) {
counted += BLOCK_SIZE(b);
/* ensure no adjacent free blocks */
block_t *n = b->next;
if (n != end_node && !IS_USED(n) &&
(uint8_t*)b + BLOCK_SIZE(b) == (uint8_t*)n) {
return false;
}
}
}
return (counted == free_bytes);
}