joeylib2/src/core/codegenArenaInternal.h

76 lines
3.2 KiB
C

// 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