// Codegen arena: a pool of executable memory that holds compiled // sprite routines. Allocator is first-fit with adjacent-hole // coalescing on free; manual compaction (codegenArenaCompact) // memmoves live slots down to consolidate free space. // // SpriteT references slots via ArenaSlotT*, never raw function // pointers. spriteDraw computes the call address each invocation as // `gArenaBase + slot->offset + routineOffsets[shift][op]` so a // compaction that moves a slot's bytes is transparent to callers. // // Allocations go through plain malloc; on every supported port // (IIgs ORCA, Amiga libnix, ST mintlib, DJGPP+CWSDPMI) the heap is // readable, writable, AND executable. We are not running in a W^X // environment. // // The arena is a process-singleton: codegenArenaInit creates it from // JoeyConfigT.codegenBytes during joeyInit; codegenArenaShutdown // frees it on joeyShutdown. Most callers should go through the // sprite API rather than touching the arena directly. #ifndef JOEYLIB_CODEGEN_ARENA_INTERNAL_H #define JOEYLIB_CODEGEN_ARENA_INTERNAL_H #include "joey/types.h" typedef struct ArenaSlotT { uint32_t offset; // byte offset within the arena base uint32_t size; // bytes occupied by this slot bool used; // true = held by a sprite; false = free struct ArenaSlotT *next; // linked-list, sorted by offset struct ArenaSlotT *prev; } ArenaSlotT; // Lifecycle. Returns false if totalBytes is 0 or the underlying // allocation fails. Idempotent: calling Init twice without an // intervening Shutdown is a no-op. bool codegenArenaInit(uint32_t totalBytes); void codegenArenaShutdown(void); // First-fit allocate `bytes` of executable memory. Returns NULL if // no free slot is large enough -- the caller should run // codegenArenaCompact and retry, or surface the failure. ArenaSlotT *codegenArenaAlloc(uint32_t bytes); // Mark the slot free and merge with adjacent free neighbors. The // caller must drop its ArenaSlotT* immediately; the struct may be // freed (if it coalesced into a neighbor). void codegenArenaFree(ArenaSlotT *slot); // Walk live slots in offset order, memmove each down to fill any // preceding hole, drop all free slots from the list, and finish with // one trailing free slot covering the remaining space. Per-slot // `offset` fields are updated atomically with the memmove so any // callers indexing through `gArenaBase + slot->offset` see the new // value on their next read. void codegenArenaCompact(void); // Used for spriteDraw's address computation. The base pointer is // stable for the lifetime of the arena; only slot->offset moves. uint8_t *codegenArenaBase(void); // Same address as codegenArenaBase() but returned as an integer. The // IIgs JSL trampoline needs the 24-bit absolute address as a number // it can split into bank/offset bytes; ORCA-C's pointer-to-uint32_t // cast has dropped the bank byte in some expressions, so we expose // the integer view directly. uint32_t codegenArenaBaseAddr(void); // Public-API support: sum of live slot sizes, total arena size. // Difference is free space (which may be fragmented across holes // until codegenArenaCompact runs). uint32_t codegenArenaBytesUsed(void); uint32_t codegenArenaBytesTotal(void); #endif