Merge pull request #7355 from samuelgozi/dynamic-arena-reused-block-alignment

mem: Keep Dynamic_Arena allocations aligned after reset
This commit is contained in:
gingerBill
2026-08-17 12:40:14 +02:00
committed by GitHub
2 changed files with 56 additions and 3 deletions

View File

@@ -1813,7 +1813,7 @@ dynamic_arena_alloc_bytes_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, align
}
memory := align_forward(a.current_pos, uintptr(actual_alignment))
margin := int(uintptr(memory) - uintptr(a.current_pos))
if a.bytes_left < margin + n {
for a.bytes_left < margin + n {
err := _dynamic_arena_cycle_new_block(a, alignment, loc)
if err != nil {
return nil, err
@@ -1821,8 +1821,8 @@ dynamic_arena_alloc_bytes_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, align
if a.current_block == nil {
return nil, .Out_Of_Memory
}
margin = 0
memory = a.current_pos
memory = align_forward(a.current_pos, uintptr(actual_alignment))
margin = int(uintptr(memory) - uintptr(a.current_pos))
}
a.current_pos = ([^]byte)(memory)[n:]
a.bytes_left -= margin + n

View File

@@ -74,6 +74,59 @@ test_dynamic_arena_alloc_unaligned :: proc(t: ^testing.T) {
expect_arena_allocation(t, expected_used_bytes = 16, num_bytes = 9, alignment = 8)
}
expect_reused_block_alignment :: proc(
t: ^testing.T,
backing: []byte,
block_size: int,
should_reuse: bool,
) {
block_arena: mem.Arena
mem.arena_init(&block_arena, backing)
arena: mem.Dynamic_Arena
mem.dynamic_arena_init(
&arena,
block_allocator = mem.arena_allocator(&block_arena),
block_size = block_size,
out_band_size = block_size + 1,
)
defer mem.dynamic_arena_destroy(&arena)
allocator := mem.dynamic_arena_allocator(&arena)
first, first_err := mem.alloc(1, 16, allocator)
testing.expect_value(t, first_err, mem.Allocator_Error.None)
testing.expect(t, uintptr(first) % 64 == 16)
mem.dynamic_arena_reset(&arena)
aligned, aligned_err := mem.alloc(1, 64, allocator)
testing.expect_value(t, aligned_err, mem.Allocator_Error.None)
testing.expect(t, uintptr(aligned) % 64 == 0)
testing.expect_value(t, arena.current_block == first, should_reuse)
}
@(test)
test_dynamic_arena_realigns_reused_block :: proc(t: ^testing.T) {
Backing :: struct #align(64) {
_: [16]byte,
data: [128]byte,
}
backing: Backing
expect_reused_block_alignment(t, backing.data[:], 128, true)
}
@(test)
test_dynamic_arena_skips_incompatible_reused_block :: proc(t: ^testing.T) {
Backing :: struct #align(64) {
_: [16]byte,
data: [176]byte,
}
backing: Backing
expect_reused_block_alignment(t, backing.data[:], 64, false)
}
@(test)
test_dynamic_arena_alloc_out_of_band :: proc(t: ^testing.T) {
expect_arena_allocation_out_of_band(t, num_bytes = 128, block_size = 512, out_band_size = 128)