//////////////////////////////// //- sixten: Common Memory Functions static void Copy(void *Dest, void *Source, umm Count) { if(Count <= S32_Max) { u8 *Dest8 = (u8 *)Dest; u8 *Source8 = (u8 *)Source; while(Count--) { *Dest8++ = *Source8++; } } } static void CopyReverse(void *Dest, void *Source, umm Count) { if(Count <= S32_Max) { u8 *Dest8 = (u8 *)Dest + Count; u8 *Source8 = (u8 *)Source + Count; while(Count--) { *--Dest8 = *--Source8; } } } static void Fill(void *Dest, u8 Value, umm Count) { if(Count <= S32_Max) { u8 *Dest8 = (u8 *)Dest; while(Count--) { *Dest8++ = Value; } } } #if VN_ASAN_ENABLED #include #endif //////////////////////////////// //- sixten: Memory Arena Functions static arena *ArenaAlloc(u64 Size, b32 Chaining, char *Format, ...) { arena *Arena = 0; if(Chaining) { void *Memory = Platform.Allocate(Size); Arena = (arena *)Memory; #if VN_ASAN_ENABLED ASAN_POISON_MEMORY_REGION(Arena, Size); ASAN_UNPOISON_MEMORY_REGION(Arena, sizeof(arena)); #endif Arena->Chaining = true; SenDLLInit(Arena); } else { u64 RoundedSize = Size+Megabytes(64)-1; RoundedSize -= RoundedSize&Megabytes(64); void *Memory = Platform.Reserve(RoundedSize); u64 InitialCommitSize = MEMORY_ARENA_COMMIT_SIZE; Platform.Commit(Memory, InitialCommitSize); Arena = (arena *)Memory; } Arena->Position = sizeof(arena); Arena->Size = Size; Arena->Align = 8; return(Arena); } static void ArenaRelease(arena *Arena) { if(Arena->Chaining) { arena *Node = Arena->Prev; for(;Node != Arena;) { arena *Next = Node->Prev; Platform.Deallocate(Node, Node->Size); Node = Next; } #if VN_ASAN_ENABLED ASAN_POISON_MEMORY_REGION(Arena, Arena->Size); #endif Platform.Deallocate(Arena, Arena->Size); } else { Platform.Release(Arena); } } static void *ArenaPushNoClear(arena *Arena, u64 Size) { void *Result = 0; if(Arena->Chaining) { if(Size <= Arena->Size) { arena *Target = Arena->Prev; // sixten: We always append to the end of the list. if(Target->Position + Size + Arena->Align > Target->Size) { arena *New = ArenaAlloc(Arena->Size, true, "Chain"); New->NotFirst = true; SenDLLInsertLast(Arena, New); Target = New; } u8 *Base = (u8 *)Target; u64 PostAlignPos = (Target->Position+Target->Align-1); PostAlignPos -= PostAlignPos%Target->Align; Result = Base + PostAlignPos; Target->Position = PostAlignPos+Size; #if VN_ASAN_ENABLED ASAN_UNPOISON_MEMORY_REGION(Result, Size); #endif } else { // sixten(NOTE): We can't really do anything in this situation. } } else { if(Arena->Position + Size <= Arena->Size) { u8 *Base = (u8 *)Arena; u64 PostAlignPos = (Arena->Position+Arena->Align-1); PostAlignPos -= PostAlignPos%Arena->Align; u64 Align = PostAlignPos - Arena->Position; Result = Base + Arena->Position + Align; Arena->Position += Size + Align; if(Arena->CommitPosition < Arena->Position) { u64 ToCommit = Arena->Position - Arena->CommitPosition; ToCommit += MEMORY_ARENA_COMMIT_SIZE - 1; ToCommit -= ToCommit%MEMORY_ARENA_COMMIT_SIZE; Platform.Commit(Base + Arena->CommitPosition, ToCommit); Arena->CommitPosition += ToCommit; } } else { InvalidCodepath; } } return(Result); } static void *ArenaPush(arena *Arena, u64 Size) { void *Result = ArenaPushNoClear(Arena, Size); Fill(Result, 0, Size); return(Result); } static void ArenaPopTo(arena *Arena, u64 Position) { if(Arena->Chaining) { // sixten: find the relevant arena arena *Target = Arena; for(int ArenaIndex = 0; ArenaIndex < Position/Arena->Size; ++ArenaIndex) { Target = Target->Next; } // sixten: deallocate all arenas that are no longer needed { arena *Node = Arena->Prev; while(Node != Target) { arena *Prev = Node->Prev; SenDLLRemove(Node); #if VN_ASAN_ENABLED ASAN_POISON_MEMORY_REGION(Node, Node->Size); #endif Platform.Deallocate(Node, Node->Size); Node = Prev; } } Target->Position = Position%Arena->Size; #if VN_ASAN_ENABLED u64 UnpoisonPosition = Target->Position; ASAN_POISON_MEMORY_REGION(Target, Target->Size); ASAN_UNPOISON_MEMORY_REGION(Target, UnpoisonPosition); #endif } else { u64 MinPosition = sizeof(*Arena); u64 NewPosition = Maximum(MinPosition, Position); Arena->Position = NewPosition; u64 CommitAlignedPosition = Arena->Position+MEMORY_ARENA_COMMIT_SIZE-1; CommitAlignedPosition -= CommitAlignedPosition%MEMORY_ARENA_COMMIT_SIZE; if(CommitAlignedPosition + MEMORY_ARENA_DECOMMIT_THRESHOLD <= Arena->CommitPosition) { u8 *Base = (u8 *)Arena; u64 ToDecommit = Arena->CommitPosition-CommitAlignedPosition; Platform.Decommit(Base+CommitAlignedPosition, ToDecommit); Arena->CommitPosition -= ToDecommit; } } } static void ArenaPop(arena *Arena, u64 Amount) { ArenaPopTo(Arena, Max(Arena->Position-Amount, (s64)sizeof(arena))); } static void ArenaClear(arena *Arena) { ArenaPopTo(Arena, sizeof(*Arena)); } static void ArenaSetAlign(arena *Arena, u64 Align) { Arena->Align = Align; } //////////////////////////////// //- sixten: Temporary Memory Functions static temp BeginTemp(arena *Arena) { temp Temp; Temp.Arena = Arena; Temp.Position = Arena->Position; return(Temp); } static void EndTemp(temp Temp) { ArenaPopTo(Temp.Arena, Temp.Position); }