155 lines
4.7 KiB
C
155 lines
4.7 KiB
C
SharedScratchCtx shared_scratch_ctx = ZI;
|
|
|
|
/* NOTE: Application will exit if arena fails to reserve or commit initial memory. */
|
|
Arena *AllocArena(u64 reserve)
|
|
{
|
|
__prof;
|
|
reserve += ArenaHeaderSize;
|
|
|
|
/* Round up to nearest block size */
|
|
u64 block_remainder = reserve % ArenaBlockSize;
|
|
if (block_remainder > 0)
|
|
{
|
|
reserve += ArenaBlockSize - block_remainder;
|
|
}
|
|
|
|
u8 *base = ReserveMemory(reserve);
|
|
if (!base)
|
|
{
|
|
/* Hard fail on memory reserve failure for now */
|
|
/* FIXME: Enable this */
|
|
//P_Panic(Lit("Failed to reserve memory"));
|
|
(*(volatile int *)0) = 0;
|
|
}
|
|
u64 reserved = reserve;
|
|
AddGstat(GSTAT_MEMORY_RESERVED, reserve);
|
|
|
|
/* Commit initial block */
|
|
base = CommitMemory(base, ArenaBlockSize);
|
|
if (!base)
|
|
{
|
|
/* Hard fail on commit failure */
|
|
/* FIXME: Enable this */
|
|
//P_Panic(Lit("Failed to commit initial memory block: System may be out of memory"));
|
|
(*(volatile int *)0) = 0;
|
|
}
|
|
|
|
Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */
|
|
StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */
|
|
StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */
|
|
|
|
__profalloc(base, ArenaBlockSize);
|
|
AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena));
|
|
AddGstat(GSTAT_MEMORY_COMMITTED, ArenaBlockSize);
|
|
AddGstat(GSTAT_NUM_ARENAS, 1);
|
|
|
|
/* Create & return arena header at beginning of block */
|
|
Arena *arena = (Arena *)base;
|
|
ZeroStruct(arena);
|
|
arena->committed = ArenaBlockSize - ArenaHeaderSize;
|
|
arena->reserved = reserved;
|
|
return arena;
|
|
}
|
|
|
|
void ReleaseArena(Arena *arena)
|
|
{
|
|
AsanUnpoison(arena, arena->committed + ArenaHeaderSize);
|
|
__prof;
|
|
__proffree(arena);
|
|
AddGstat(GSTAT_MEMORY_COMMITTED, -(i64)(arena->committed - ArenaHeaderSize));
|
|
AddGstat(GSTAT_MEMORY_RESERVED, -(i64)(arena->reserved));
|
|
AddGstat(GSTAT_NUM_ARENAS, -1);
|
|
ReleaseMemory(arena);
|
|
}
|
|
|
|
/* NOTE: Application will exit if arena fails to commit memory */
|
|
void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
|
|
{
|
|
Assert(align > 0);
|
|
Assert(!arena->readonly);
|
|
|
|
void *ptr = 0;
|
|
u8 *base = ArenaBase(arena);
|
|
|
|
/* Check to avoid aligning when size = 0 */
|
|
if (size > 0)
|
|
{
|
|
u64 aligned_start_pos = (arena->pos + (align - 1));
|
|
aligned_start_pos -= aligned_start_pos % align;
|
|
|
|
u64 new_pos = aligned_start_pos + size;
|
|
if (new_pos > arena->committed)
|
|
{
|
|
__profn("Arena commit");
|
|
/* Commit new block(s) */
|
|
u64 blocks_needed = (new_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize;
|
|
u64 commit_bytes = blocks_needed * ArenaBlockSize;
|
|
u64 new_capacity = arena->committed + commit_bytes;
|
|
if (new_capacity > arena->reserved)
|
|
{
|
|
/* Hard fail if we overflow reserved memory for now */
|
|
/* FIXME: Enable this */
|
|
//P_Panic(Lit("Failed to commit new memory block: Overflow of reserved memory"));
|
|
(*(volatile int *)0) = 0;
|
|
}
|
|
void *commit_address = base + arena->committed;
|
|
if (!CommitMemory(commit_address, commit_bytes))
|
|
{
|
|
/* Hard fail on memory allocation failure for now */
|
|
/* FIXME: Enable this */
|
|
//P_Panic(Lit("Failed to commit new memory block: System may be out of memory"));
|
|
(*(volatile int *)0) = 0;
|
|
}
|
|
arena->committed += commit_bytes;
|
|
AddGstat(GSTAT_MEMORY_COMMITTED, commit_bytes);
|
|
__proffree(arena);
|
|
__profalloc(arena, arena->committed + ArenaHeaderSize);
|
|
AsanPoison(commit_address, commit_bytes);
|
|
}
|
|
|
|
ptr = base + aligned_start_pos;
|
|
AsanUnpoison(ptr, new_pos - aligned_start_pos);
|
|
arena->pos = new_pos;
|
|
}
|
|
else
|
|
{
|
|
ptr = base + arena->pos;
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
/* Copies the memory from the source arena into the destination arena,
|
|
* replacing old contents. Destination arena will be expanded if necessary. */
|
|
void CopyArena(Arena *dst, Arena *src)
|
|
{
|
|
ResetArena(dst);
|
|
u64 data_size = src->pos;
|
|
u8 *data_src = ArenaBase(src);
|
|
u8 *data_dst = PushBytesNoZero(dst, data_size, 1);
|
|
CopyBytes(data_dst, data_src, data_size);
|
|
}
|
|
|
|
void ShrinkArena(Arena *arena)
|
|
{
|
|
/* Not implemented */
|
|
Assert(0);
|
|
LAX arena;
|
|
}
|
|
|
|
void SetArenaReadonly(Arena *arena)
|
|
{
|
|
#if RtcIsEnabled
|
|
arena->readonly = 1;
|
|
#endif
|
|
SetMemoryReadonly(arena, arena->committed + ArenaHeaderSize);
|
|
}
|
|
|
|
void SetArenaReadWrite(Arena *arena)
|
|
{
|
|
SetMemoryReadWrite(arena, arena->committed + ArenaHeaderSize);
|
|
#if RtcIsEnabled
|
|
arena->readonly = 0;
|
|
#endif
|
|
}
|