From 98076363592cd9605b92c2074813c28793308874 Mon Sep 17 00:00:00 2001 From: Judah Caruso Date: Sat, 31 Jan 2026 13:38:18 -0700 Subject: [PATCH] arena: add Fixed which is just Linear that doesn't allocate its backing memory, rename Paging to Paged --- arena/arenas.go | 52 ++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/arena/arenas.go b/arena/arenas.go index c02c41a..2bc362f 100644 --- a/arena/arenas.go +++ b/arena/arenas.go @@ -12,22 +12,21 @@ import ( "git.brut.systems/judah/xx/mem" ) -// Linear is a simple bump allocator with a fixed amount of backing memory. -func Linear(capacity_in_bytes uintptr) Arena { - if capacity_in_bytes <= 0 { - panic("linear: capacity_in_bytes must be greater than zero") +// Fixed is a simple bump allocator that uses the given buffer. +// +// Fixed will NOT resize when it runs out of memory. +func Fixed(data []byte) Arena { + if len(data) == 0 || len(data) != cap(data) { + panic("fixed: length & capacity must be equal and greater than zero") } - var ( - data = make([]byte, capacity_in_bytes) - offset uintptr - ) + var offset uintptr return func(a Action, size, align uintptr, watermark *uintptr) (unsafe.Pointer, error) { switch a { case ACTION_ALLOC: aligned := mem.AlignForward(size, align) - if offset+aligned > capacity_in_bytes { - return nil, errors.New("linear: out of memory") + if offset+aligned > uintptr(cap(data)) { + return nil, errors.New("fixed: out of memory") } ptr := &data[offset] @@ -38,25 +37,30 @@ func Linear(capacity_in_bytes uintptr) Arena { offset = 0 case ACTION_SAVE: if watermark == nil { - return nil, errors.New("linear: cannot save to nil watermark") + return nil, errors.New("fixed: cannot save to nil watermark") } *watermark = offset case ACTION_RESTORE: if watermark == nil { - return nil, errors.New("linear: cannot restore nil watermark") + return nil, errors.New("fixed: cannot restore nil watermark") } clear(data[*watermark:offset]) offset = *watermark default: - panic("linear: unimplemented action - " + a.String()) + panic("fixed: unimplemented action - " + a.String()) } return nil, nil } } +// Linear is a simple bump allocator with a fixed amount of backing memory. +func Linear(capacity_in_bytes uintptr) Arena { + return Fixed(make([]byte, capacity_in_bytes)) +} + // Ring is an Arena that only allocates values of the given type. // When capacity is exceeded, previous allocations will be reused to accommodate new ones // @@ -172,12 +176,12 @@ func Chunked(max_allocs_per_chunk uintptr) Arena { } } -// Paging is a linear arena that allocates pages of virtual memory. +// Paged is a linear arena that allocates pages of virtual memory. // The memory allocated is only committed to physical memory as it is used, // so total_reserved_in_bytes should is the total amount of addressable memory to reserve. // -// Note: resetting a Paging arena will cause the currently commited memory to be decommited (i.e. unmapped from physical memory). -func Paging(page_size, total_reserved_in_bytes uintptr) Arena { +// Note: resetting a Paged arena will cause the currently commited memory to be decommited (i.e. unmapped from physical memory). +func Paged(page_size, total_reserved_in_bytes uintptr) Arena { var ( committed uintptr offset uintptr @@ -185,13 +189,13 @@ func Paging(page_size, total_reserved_in_bytes uintptr) Arena { base, err := mem.Reserve(total_reserved_in_bytes) if err != nil { - panic(fmt.Sprintf("paging: failed to reserve address space - %s", err)) + panic(fmt.Sprintf("paged: failed to reserve address space - %s", err)) } // @todo(judah): is this needed? runtime.AddCleanup(&base, func(_ struct{}) { if err := mem.Release(base); err != nil { - panic(fmt.Sprintf("paging: failed to release memory - %s", err)) + panic(fmt.Sprintf("paged: failed to release memory - %s", err)) } }, struct{}{}) @@ -200,7 +204,7 @@ func Paging(page_size, total_reserved_in_bytes uintptr) Arena { case ACTION_ALLOC: aligned := mem.AlignForward(size, align) if offset+aligned > total_reserved_in_bytes { - return nil, errors.New("paging: out of addressable memory") + return nil, errors.New("paged: out of addressable memory") } if offset+aligned > committed { @@ -208,7 +212,7 @@ func Paging(page_size, total_reserved_in_bytes uintptr) Arena { to_commit := mem.AlignForward(required, page_size) if err := mem.Commit(base[committed:to_commit-committed], mem.AccessRead|mem.AccessWrite); err != nil { - return nil, fmt.Errorf("paging: failed to commit memory - %w", err) + return nil, fmt.Errorf("paged: failed to commit memory - %w", err) } committed = to_commit @@ -221,7 +225,7 @@ func Paging(page_size, total_reserved_in_bytes uintptr) Arena { case ACTION_RESET: if committed > 0 { if err := mem.Decommit(base[:mem.AlignForward(committed, page_size)]); err != nil { - return nil, fmt.Errorf("paging: failed to decommit memory - %w", err) + return nil, fmt.Errorf("paged: failed to decommit memory - %w", err) } } @@ -233,7 +237,7 @@ func Paging(page_size, total_reserved_in_bytes uintptr) Arena { case ACTION_SAVE: if watermark == nil { - return nil, errors.New("paging: cannot save to nil watermark") + return nil, errors.New("paged: cannot save to nil watermark") } *watermark = offset @@ -241,7 +245,7 @@ func Paging(page_size, total_reserved_in_bytes uintptr) Arena { case ACTION_RESTORE: if watermark == nil { - return nil, errors.New("paging: cannot restore nil watermark") + return nil, errors.New("paged: cannot restore nil watermark") } clear(base[*watermark:offset]) @@ -250,7 +254,7 @@ func Paging(page_size, total_reserved_in_bytes uintptr) Arena { return nil, nil default: - panic("paging: unimplemented action - " + a.String()) + panic("paged: unimplemented action - " + a.String()) } } }