Skip to content

Commit

Permalink
Added support for growing in place to some arenas.
Browse files Browse the repository at this point in the history
This affects `runtime.Arena` and `virtual.Arena`, but not currently
`mem.Arena`. These changes allow the last allocation that has been
made to be resized to a larger size by just extending their
allocation in-place, when there's sufficient room in the memory block to
do so.

Shrinking in place and re-using the rest of the allocation can be
supported using almost the same logic, but would require the memory to
be zeroed. Since this would add a additional cost that isn't currently
present, shrinking has not been changed.
  • Loading branch information
Barinzaya committed Jan 24, 2025
1 parent 3a13c59 commit 98b3a9e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
22 changes: 18 additions & 4 deletions base/runtime/default_temp_allocator_arena.odin
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,24 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
case size == 0:
err = .Mode_Not_Implemented
return
case (uintptr(old_data) & uintptr(alignment-1) == 0) && size < old_size:
// shrink data in-place
data = old_data[:size]
return
case uintptr(old_data) & uintptr(alignment-1) == 0:
if size < old_size {
// shrink data in-place
data = old_data[:size]
return
}

if block := arena.curr_block; block != nil {
start := uint(uintptr(old_memory)) - uint(uintptr(block.base))
old_end := start + old_size
new_end := start + size
if start < old_end && old_end == block.used && new_end <= block.capacity {
// grow data in-place, adjusting next allocation
block.used = uint(new_end)
data = block.base[start:new_end]
return
}
}
}

new_memory := arena_alloc(arena, size, alignment, location) or_return
Expand Down
22 changes: 18 additions & 4 deletions core/mem/virtual/arena.odin
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,24 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
case size == 0:
err = .Mode_Not_Implemented
return
case (uintptr(old_data) & uintptr(alignment-1) == 0) && size < old_size:
// shrink data in-place
data = old_data[:size]
return
case uintptr(old_data) & uintptr(alignment-1) == 0:
if size < old_size {
// shrink data in-place
data = old_data[:size]
return
}

if block := arena.curr_block; block != nil {
start := uint(uintptr(old_memory)) - uint(uintptr(block.base))
old_end := start + old_size
new_end := start + size
if start < old_end && old_end == block.used && new_end <= block.reserved {
// grow data in-place, adjusting next allocation
_ = alloc_from_memory_block(block, new_end - old_end, 1, default_commit_size=arena.default_commit_size) or_return
data = block.base[start:new_end]
return
}
}
}

new_memory := arena_alloc(arena, size, alignment, location) or_return
Expand Down

0 comments on commit 98b3a9e

Please sign in to comment.