77 lines
3.3 KiB
C
77 lines
3.3 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.
|
|
//
|
|
// jlSpriteT references slots via ArenaSlotT*, never raw function
|
|
// pointers. jlSpriteDraw 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, 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
|
|
// jlConfigT.codegenBytes during jlInit; codegenArenaShutdown
|
|
// frees it on jlShutdown. 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 jlSpriteDraw's address computation. The base pointer is
|
|
// stable for the lifetime of the arena; only slot->offset moves.
|
|
//
|
|
// Direct extern access (instead of a getter function) so per-frame
|
|
// hot paths in jlSpriteCompile.c skip the JSL/PHB/RTL/PLB the wrapper
|
|
// would impose. Both globals are read-only after codegenArenaInit;
|
|
// the function-form getters below are kept as a back-compat shim.
|
|
extern uint8_t *gCodegenArenaBase;
|
|
extern uint32_t gCodegenArenaBaseAddr;
|
|
#define codegenArenaBase() ((uint8_t *)gCodegenArenaBase)
|
|
#define codegenArenaBaseAddr() ((uint32_t)gCodegenArenaBaseAddr)
|
|
|
|
// 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
|