Breaking Change: Allocator_Packed_Info as part of the Allocator_Proc interface to minimize register use with calls

This commit is contained in:
gingerBill
2026-07-08 12:47:50 +01:00
parent 1e0ab53e92
commit 2c364980af
22 changed files with 165 additions and 125 deletions

View File

@@ -420,9 +420,17 @@ Allocator_Error :: enum byte {
Multiplication_Overflow_On_Requested_Size = 5,
}
Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int,
Allocator_Packed_Info :: struct {
mode: Allocator_Mode,
log2_alignment: u8,
}
// NOTE(bill): Allocator_Packed_Info could be packed even further to 8 bits (3:mode + 5:log2_alignment)
// but this is not benefiting any ABI whatsoever to minimize it furthers
#assert(size_of(Allocator_Packed_Info) == 2)
Allocator_Proc :: #type proc(allocator_data: rawptr, packed_info: Allocator_Packed_Info,
size: int, old_memory: rawptr, old_size: int,
location: Source_Code_Location = #caller_location) -> ([]byte, Allocator_Error)
Allocator :: struct {
procedure: Allocator_Proc,

View File

@@ -651,7 +651,8 @@ make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := con
byte_count, overflows := intrinsics.overflow_mul(size_of(E), len)
if overflows {
return .Multiplication_Overflow_On_Requested_Size
err = .Multiplication_Overflow_On_Requested_Size
return
}
data := mem_alloc_bytes(byte_count, align_of(E), allocator, loc) or_return

View File

@@ -1,9 +1,8 @@
package runtime
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
switch mode {
nil_allocator_proc :: proc(allocator_data: rawptr, packed_info: Allocator_Packed_Info,
size: int, old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
switch packed_info.mode {
case .Alloc, .Alloc_Non_Zeroed:
return nil, .Out_Of_Memory
case .Free:
@@ -40,10 +39,9 @@ nil_allocator :: proc "contextless" () -> Allocator {
}
panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
switch mode {
panic_allocator_proc :: proc(allocator_data: rawptr, packed_info: Allocator_Packed_Info,
size: int, old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
switch packed_info.mode {
case .Alloc:
if size > 0 {
panic("panic allocator, .Alloc called", loc=loc)

View File

@@ -183,16 +183,15 @@ arena_allocator :: proc(arena: ^Arena) -> Allocator {
return Allocator{arena_allocator_proc, arena}
}
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int,
arena_allocator_proc :: proc(allocator_data: rawptr, packed_info: Allocator_Packed_Info,
size: int, old_memory: rawptr, old_size: int,
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
arena := (^Arena)(allocator_data)
size, alignment := uint(size), uint(alignment)
size, alignment := uint(size), uint(1)<<packed_info.log2_alignment
old_size := uint(old_size)
switch mode {
switch packed_info.mode {
case .Alloc, .Alloc_Non_Zeroed:
return arena_alloc(arena, size, alignment, location)
case .Free:

View File

@@ -41,12 +41,11 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
}
}
default_temp_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
default_temp_allocator_proc :: proc(allocator_data: rawptr, packed_info: Allocator_Packed_Info,
size: int, old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
s := (^Default_Temp_Allocator)(allocator_data)
return arena_allocator_proc(&s.arena, mode, size, alignment, old_memory, old_size, loc)
return arena_allocator_proc(&s.arena, packed_info, size, old_memory, old_size, loc)
}
@(require_results)

View File

@@ -10,8 +10,8 @@ heap_allocator :: proc() -> Allocator {
}
}
heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
heap_allocator_proc :: proc(allocator_data: rawptr, packed_info: Allocator_Packed_Info,
size: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
//
// NOTE(tetra, 2020-01-14): The heap doesn't respect alignment.
@@ -20,6 +20,9 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
// the pointer we return to the user.
//
mode := packed_info.mode
alignment := int(1)<<packed_info.log2_alignment
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr, old_size: int, zero_memory := true) -> ([]byte, Allocator_Error) {
// Not(flysand): We need to reserve enough space for alignment, which
// includes the user data itself, the space to store the pointer to

View File

@@ -30,6 +30,15 @@ NATIVE_SIMD_BIT_WIDTH ::
// Fallback for no hardware SIMD, but also SSE, NEON, SVE, RVV and WASM SIMD128.
128
@(require_results)
_u8_log2 :: proc "contextless" (x: $T) -> (res: u8) where intrinsics.type_is_integer(T) {
if x <= 0 {
return 0
}
return u8((8*size_of(T)-1) - intrinsics.count_leading_zeros(x))
}
@(private)
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte #no_bounds_check {
return ([^]byte)(data)[:max(len, 0)]
@@ -119,7 +128,7 @@ mem_alloc_bytes :: #force_no_inline proc(size: int, alignment: int = DEFAULT_ALI
if size == 0 || allocator.procedure == nil{
return nil, nil
}
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
return allocator.procedure(allocator.data, {.Alloc, _u8_log2(alignment)}, size, nil, 0, loc)
}
mem_alloc :: #force_no_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
@@ -127,7 +136,7 @@ mem_alloc :: #force_no_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT
if size == 0 || allocator.procedure == nil {
return nil, nil
}
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
return allocator.procedure(allocator.data, {.Alloc, _u8_log2(alignment)}, size, nil, 0, loc)
}
mem_alloc_non_zeroed :: #force_no_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
@@ -135,7 +144,7 @@ mem_alloc_non_zeroed :: #force_no_inline proc(size: int, alignment: int = DEFAUL
if size == 0 || allocator.procedure == nil {
return nil, nil
}
return allocator.procedure(allocator.data, .Alloc_Non_Zeroed, size, alignment, nil, 0, loc)
return allocator.procedure(allocator.data, {.Alloc_Non_Zeroed, _u8_log2(alignment)}, size, nil, 0, loc)
}
@builtin
@@ -143,7 +152,7 @@ mem_free :: #force_no_inline proc(ptr: rawptr, allocator := context.allocator, l
if ptr == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc)
_, err := allocator.procedure(allocator.data, {.Free, 0}, 0, ptr, 0, loc)
return err
}
@@ -151,7 +160,7 @@ mem_free_with_size :: #force_no_inline proc(ptr: rawptr, byte_count: int, alloca
if ptr == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, byte_count, loc)
_, err := allocator.procedure(allocator.data, {.Free, 0}, 0, ptr, byte_count, loc)
return err
}
@@ -159,67 +168,66 @@ mem_free_bytes :: #force_no_inline proc(bytes: []byte, allocator := context.allo
if bytes == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, raw_data(bytes), len(bytes), loc)
_, err := allocator.procedure(allocator.data, {.Free, 0}, 0, raw_data(bytes), len(bytes), loc)
return err
}
@builtin
mem_free_all :: #force_no_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) {
if allocator.procedure != nil {
_, err = allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc)
_, err = allocator.procedure(allocator.data, {.Free_All, 0}, 0, nil, 0, loc)
}
return
}
_mem_resize :: #force_no_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, should_zero: bool, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
_mem_resize :: #force_no_inline proc(ptr: rawptr, old_size, new_size: int, log2_alignment: u8, allocator := context.allocator, should_zero: bool, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
if allocator.procedure == nil {
return nil, nil
}
if new_size == 0 {
if ptr != nil {
_, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
_, err = allocator.procedure(allocator.data, {.Free, log2_alignment}, 0, ptr, old_size, loc)
return
}
return
} else if ptr == nil {
if should_zero {
return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
return allocator.procedure(allocator.data, {.Alloc, log2_alignment}, new_size, nil, 0, loc)
} else {
return allocator.procedure(allocator.data, .Alloc_Non_Zeroed, new_size, alignment, nil, 0, loc)
return allocator.procedure(allocator.data, {.Alloc_Non_Zeroed, log2_alignment}, new_size, nil, 0, loc)
}
} else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 {
} else if old_size == new_size && uintptr(ptr) % (uintptr(1)<<log2_alignment) == 0 {
data = ([^]byte)(ptr)[:old_size]
return
}
if should_zero {
data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
data, err = allocator.procedure(allocator.data, {.Resize, log2_alignment}, new_size, ptr, old_size, loc)
} else {
data, err = allocator.procedure(allocator.data, .Resize_Non_Zeroed, new_size, alignment, ptr, old_size, loc)
data, err = allocator.procedure(allocator.data, {.Resize_Non_Zeroed, log2_alignment}, new_size, ptr, old_size, loc)
}
if err == .Mode_Not_Implemented {
if should_zero {
data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
data, err = allocator.procedure(allocator.data, {.Alloc, log2_alignment}, new_size, nil, 0, loc)
} else {
data, err = allocator.procedure(allocator.data, .Alloc_Non_Zeroed, new_size, alignment, nil, 0, loc)
data, err = allocator.procedure(allocator.data, {.Alloc_Non_Zeroed, log2_alignment}, new_size, nil, 0, loc)
}
if err != nil {
return
}
copy(data, ([^]byte)(ptr)[:old_size])
_, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
_, err = allocator.procedure(allocator.data, {.Free, log2_alignment}, 0, ptr, old_size, loc)
}
return
}
mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
return _mem_resize(ptr, old_size, new_size, alignment, allocator, true, loc)
return _mem_resize(ptr, old_size, new_size, _u8_log2(alignment), allocator, true, loc)
}
non_zero_mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
return _mem_resize(ptr, old_size, new_size, alignment, allocator, false, loc)
return _mem_resize(ptr, old_size, new_size, _u8_log2(alignment), allocator, false, loc)
}
conditional_mem_zero :: proc "contextless" (data: rawptr, n_: int) #no_bounds_check {

View File

@@ -59,19 +59,22 @@ log_allocator :: proc(la: ^Log_Allocator) -> runtime.Allocator {
// Backing procedure for allocator that logs all allocations.
log_allocator_proc :: proc(allocator_data: rawptr,
size, alignment: int,
old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error) {
la := (^Log_Allocator)(allocator_data)
packed_info: runtime.Allocator_Packed_Info,
size: int, old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error) {
la := (^Log_Allocator)(allocator_data)
if context.logger.procedure == nil || la.level < context.logger.lowest_level {
return la.allocator.procedure(la.allocator.data, packed_info, size, old_memory, old_size, location)
}
}
padding := " " if la.prefix != "" else ""
buf: [256]byte = ---
mode := packed_info.mode
alignment := 1<<packed_info.log2_alignment
sync.lock(&la.lock)
switch mode {
case .Alloc:
format: string
@@ -138,7 +141,7 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
sync.unlock(&la.lock)
data, err := la.allocator.procedure(la.allocator.data, packed_info, size, old_memory, old_size, location)
if err != nil {
if err != nil {
sync.lock(&la.lock)
str := fmt.bprintf(buf[:], "%s%sALLOCATOR ERROR=%v", la.prefix, padding, err)
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)

View File

@@ -119,6 +119,7 @@ Error :: enum byte {
Invalid_Pointer = 2,
Invalid_Argument = 3,
Mode_Not_Implemented = 4, // Allocation
Multiplication_Overflow_On_Requested_Size = 5,
Assignment_To_Immutable = 10,
Max_Iterations_Reached = 11,
@@ -147,6 +148,7 @@ Error_String :: #sparse[Error]string{
.Invalid_Pointer = "Invalid pointer",
.Invalid_Argument = "Invalid argument",
.Mode_Not_Implemented = "Allocation mode not implemented",
.Multiplication_Overflow_On_Requested_Size = "Multiplication overflow on requested allocation size",
.Assignment_To_Immutable = "Assignment to immutable",
.Max_Iterations_Reached = "Max iterations reached",

View File

@@ -246,6 +246,9 @@ is defined as follows:
*/
Allocator :: runtime.Allocator
Allocator_Packed_Info :: runtime.Allocator_Packed_Info
/*
Default alignment.
@@ -709,7 +712,7 @@ Query allocator features.
@(require_results)
query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
if allocator.procedure != nil {
allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc)
allocator.procedure(allocator.data, {.Query_Features, 0}, 0, &set, 0, loc)
return set
}
return nil
@@ -726,7 +729,7 @@ query_info :: proc(
) -> (props: Allocator_Query_Info) {
props.pointer = pointer
if allocator.procedure != nil {
allocator.procedure(allocator.data, .Query_Info, 0, 0, &props, 0, loc)
allocator.procedure(allocator.data, {.Query_Info, 0}, 0, &props, 0, loc)
}
return
}

View File

@@ -71,8 +71,8 @@ nil_allocator :: proc() -> Allocator {
nil_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
size, alignment: int,
packed_info: Allocator_Packed_Info,
size: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
@@ -98,13 +98,13 @@ panic_allocator :: proc() -> Allocator {
panic_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
size, alignment: int,
packed_info: Allocator_Packed_Info,
size: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
) -> ([]byte, Allocator_Error) {
switch mode {
switch packed_info.mode {
case .Alloc:
if size > 0 {
panic("mem: panic allocator, .Alloc called", loc=loc)
@@ -291,14 +291,15 @@ arena_free_all :: proc(a: ^Arena) {
arena_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
packed_info: Allocator_Packed_Info,
size: int,
alignment: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
) -> ([]byte, Allocator_Error) {
arena := cast(^Arena)allocator_data
mode := packed_info.mode
alignment := 1<<packed_info.log2_alignment
switch mode {
case .Alloc:
return arena_alloc_bytes(arena, size, alignment, loc)
@@ -772,14 +773,16 @@ scratch_resize_bytes_non_zeroed :: proc(
}
scratch_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr,
old_size: int,
allocator_data: rawptr,
packed_info: Allocator_Packed_Info,
size: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
) -> ([]byte, Allocator_Error) {
s := (^Scratch)(allocator_data)
mode := packed_info.mode
alignment := 1<<packed_info.log2_alignment
size := size
switch mode {
case .Alloc:
@@ -1190,9 +1193,8 @@ stack_resize_bytes_non_zeroed :: proc(
stack_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
packed_info: Allocator_Packed_Info,
size: int,
alignment: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
@@ -1201,7 +1203,8 @@ stack_allocator_proc :: proc(
if s.data == nil {
return nil, .Invalid_Argument
}
switch mode {
alignment := 1<<packed_info.log2_alignment
switch packed_info.mode {
case .Alloc:
return stack_alloc_bytes(s, size, alignment, loc)
case .Alloc_Non_Zeroed:
@@ -1585,18 +1588,19 @@ small_stack_resize_bytes_non_zeroed :: proc(
}
small_stack_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr,
old_size: int,
allocator_data: rawptr,
packed_info: Allocator_Packed_Info,
size: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
) -> ([]byte, Allocator_Error) {
s := cast(^Small_Stack)allocator_data
if s.data == nil {
return nil, .Invalid_Argument
}
switch mode {
alignment := 1<<packed_info.log2_alignment
switch packed_info.mode {
case .Alloc:
return small_stack_alloc_bytes(s, size, alignment, loc)
case .Alloc_Non_Zeroed:
@@ -1725,12 +1729,13 @@ _dynamic_arena_cycle_new_block :: proc(a: ^Dynamic_Arena, alignment: int, loc :=
if len(a.unused_blocks) > 0 {
new_block = pop(&a.unused_blocks)
} else {
log2_alignment := runtime._u8_log2(max(a.minimum_alignment, alignment))
data: []byte
data, err = a.block_allocator.procedure(
a.block_allocator.data,
Allocator_Mode.Alloc,
{.Alloc, log2_alignment},
a.block_size,
max(a.minimum_alignment, alignment),
nil,
0,
)
@@ -2001,15 +2006,15 @@ dynamic_arena_resize_bytes_non_zeroed :: proc(
dynamic_arena_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
packed_info: Allocator_Packed_Info,
size: int,
alignment: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
) -> ([]byte, Allocator_Error) {
arena := (^Dynamic_Arena)(allocator_data)
switch mode {
alignment := 1<<packed_info.log2_alignment
switch packed_info.mode {
case .Alloc:
return dynamic_arena_alloc_bytes(arena, size, alignment, loc)
case .Alloc_Non_Zeroed:
@@ -2362,15 +2367,16 @@ buddy_allocator_free_all :: proc(b: ^Buddy_Allocator) {
@(no_sanitize_address)
buddy_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr,
old_size: int,
allocator_data: rawptr,
packed_info: Allocator_Packed_Info,
size: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
) -> ([]byte, Allocator_Error) {
b := (^Buddy_Allocator)(allocator_data)
switch mode {
alignment := 1<<packed_info.log2_alignment
switch packed_info.mode {
case .Alloc:
return buddy_allocator_alloc_bytes(b, uint(size))
case .Alloc_Non_Zeroed:
@@ -2431,9 +2437,8 @@ compat_allocator :: proc(rra: ^Compat_Allocator) -> Allocator {
}
}
compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int,
compat_allocator_proc :: proc(allocator_data: rawptr, packed_info: Allocator_Packed_Info,
size: int, old_memory: rawptr, old_size: int,
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
Header :: struct {
size: int,
@@ -2448,6 +2453,9 @@ compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return header
}
mode := packed_info.mode
alignment := 1<<packed_info.log2_alignment
rra := (^Compat_Allocator)(allocator_data)
switch mode {
case .Alloc, .Alloc_Non_Zeroed:
@@ -2455,7 +2463,7 @@ compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
req_size := size + a
assert(req_size >= 0, "overflow")
allocation := rra.parent.procedure(rra.parent.data, mode, req_size, alignment, old_memory, old_size, location) or_return
allocation := rra.parent.procedure(rra.parent.data, {mode, runtime._u8_log2(a)}, req_size, old_memory, old_size, location) or_return
#no_bounds_check data = allocation[a:]
([^]Header)(raw_data(data))[-1] = {
@@ -2472,7 +2480,7 @@ compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
orig_ptr := rawptr(uintptr(old_memory)-uintptr(a))
orig_size := header.size + a
return rra.parent.procedure(rra.parent.data, mode, orig_size, header.alignment, orig_ptr, orig_size, location)
return rra.parent.procedure(rra.parent.data, {mode, runtime._u8_log2(header.alignment)}, orig_size, orig_ptr, orig_size, location)
case .Resize, .Resize_Non_Zeroed:
header := get_unpoisoned_header(old_memory)
@@ -2486,7 +2494,7 @@ compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
req_size := size + a
assert(size >= 0, "overflow")
allocation := rra.parent.procedure(rra.parent.data, mode, req_size, new_alignment, orig_ptr, orig_size, location) or_return
allocation := rra.parent.procedure(rra.parent.data, {mode, runtime._u8_log2(new_alignment)}, req_size, orig_ptr, orig_size, location) or_return
#no_bounds_check data = allocation[a:]
([^]Header)(raw_data(data))[-1] = {
@@ -2498,7 +2506,7 @@ compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return
case .Free_All:
return rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location)
return rra.parent.procedure(rra.parent.data, {mode, runtime._u8_log2(alignment)}, size, old_memory, old_size, location)
case .Query_Info:
info := (^Allocator_Query_Info)(old_memory)
@@ -2510,7 +2518,7 @@ compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return
case .Query_Features:
data, err = rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location)
data, err = rra.parent.procedure(rra.parent.data, {mode, runtime._u8_log2(alignment)}, size, old_memory, old_size, location)
if err != nil {
set := (^Allocator_Mode_Set)(old_memory)
set^ += {.Query_Info}

View File

@@ -38,15 +38,14 @@ mutex_allocator :: proc(m: ^Mutex_Allocator) -> Allocator {
mutex_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
packed_info: Allocator_Packed_Info,
size: int,
alignment: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
) -> (result: []byte, err: Allocator_Error) {
m := (^Mutex_Allocator)(allocator_data)
sync.mutex_guard(&m.mutex)
return m.backing.procedure(m.backing.data, mode, size, alignment, old_memory, old_size, loc)
return m.backing.procedure(m.backing.data, packed_info, size, old_memory, old_size, loc)
}

View File

@@ -458,14 +458,15 @@ rollback_stack_allocator :: proc(stack: ^Rollback_Stack) -> Allocator {
@(require_results, no_sanitize_address)
rollback_stack_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
size, alignment: int,
packed_info: Allocator_Packed_Info,
size: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
) -> (result: []byte, err: Allocator_Error) {
stack := cast(^Rollback_Stack)allocator_data
switch mode {
alignment := 1<<packed_info.log2_alignment
switch packed_info.mode {
case .Alloc:
return rb_alloc_bytes(stack, size, alignment, loc)
case .Alloc_Non_Zeroed:

View File

@@ -137,8 +137,8 @@ destroy :: proc(control: ^Allocator) {
}
}
allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
size, alignment: int,
allocator_proc :: proc(allocator_data: rawptr, packed_info: runtime.Allocator_Packed_Info,
size: int,
old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error) {
control := (^Allocator)(allocator_data)
@@ -146,11 +146,13 @@ allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
return nil, .Invalid_Argument
}
switch mode {
alignment := uint(1)<<packed_info.log2_alignment
switch packed_info.mode {
case .Alloc:
return alloc_bytes(control, uint(size), uint(alignment))
return alloc_bytes(control, uint(size), alignment)
case .Alloc_Non_Zeroed:
return alloc_bytes_non_zeroed(control, uint(size), uint(alignment))
return alloc_bytes_non_zeroed(control, uint(size), alignment)
case .Free:
free_with_size(control, old_memory, uint(old_size))
@@ -161,10 +163,10 @@ allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
return nil, nil
case .Resize:
return resize(control, old_memory, uint(old_size), uint(size), uint(alignment))
return resize(control, old_memory, uint(old_size), uint(size), alignment)
case .Resize_Non_Zeroed:
return resize_non_zeroed(control, old_memory, uint(old_size), uint(size), uint(alignment))
return resize_non_zeroed(control, old_memory, uint(old_size), uint(size), alignment)
case .Query_Features:
set := (^runtime.Allocator_Mode_Set)(old_memory)

View File

@@ -192,8 +192,8 @@ tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
@(no_sanitize_address)
tracking_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
size, alignment: int,
packed_info: Allocator_Packed_Info,
size: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
@@ -216,6 +216,8 @@ tracking_allocator_proc :: proc(
}
data := (^Tracking_Allocator)(allocator_data)
mode := packed_info.mode
alignment := 1<<packed_info.log2_alignment
sync.mutex_guard(&data.mutex)
@@ -237,7 +239,7 @@ tracking_allocator_proc :: proc(
data.bad_free_callback(data, old_memory, loc)
}
} else {
result = data.backing.procedure(data.backing.data, mode, size, alignment, old_memory, old_size, loc) or_return
result = data.backing.procedure(data.backing.data, packed_info, size, old_memory, old_size, loc) or_return
}
result_ptr := raw_data(result)

View File

@@ -326,13 +326,15 @@ arena_allocator :: proc(arena: ^Arena) -> mem.Allocator {
// The allocator procedure used by an `Allocator` produced by `arena_allocator`
@(no_sanitize_address)
arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
size, alignment: int,
arena_allocator_proc :: proc(allocator_data: rawptr, packed_info: mem.Allocator_Packed_Info,
size: int,
old_memory: rawptr, old_size: int,
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
arena := (^Arena)(allocator_data)
size, alignment := uint(size), uint(alignment)
mode := packed_info.mode
size, alignment := uint(size), uint(1)<<packed_info.log2_alignment
old_size := uint(old_size)
switch mode {

View File

@@ -108,6 +108,7 @@ error_string :: proc(ferr: Error) -> string {
case .Invalid_Pointer: return "invalid allocator pointer"
case .Invalid_Argument: return "invalid allocator argument"
case .Mode_Not_Implemented: return "allocator mode not implemented"
case .Multiplication_Overflow_On_Requested_Size: return "multiplication overflow on requested allocation size"
}
case Platform_Error:
return _error_string(i32(e))

View File

@@ -15,8 +15,7 @@ heap_allocator :: proc() -> runtime.Allocator {
@(require_results)
heap_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, runtime.Allocator_Error) {
return _heap_allocator_proc(allocator_data, mode, size, alignment, old_memory, old_size, loc)
heap_allocator_proc :: proc(allocator_data: rawptr, packed_info: runtime.Allocator_Packed_Info,
size: int, old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, runtime.Allocator_Error) {
return _heap_allocator_proc(allocator_data, packed_info, size, old_memory, old_size, loc)
}

View File

@@ -26,9 +26,8 @@ heap_free :: proc(ptr: rawptr) {
win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
}
_heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, mem.Allocator_Error) {
_heap_allocator_proc :: proc(allocator_data: rawptr, packed_info: mem.Allocator_Packed_Info,
size: int, old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, mem.Allocator_Error) {
//
// NOTE(tetra, 2020-01-14): The heap doesn't respect alignment.
// Instead, we overallocate by `alignment + size_of(rawptr) - 1`, and insert
@@ -75,6 +74,9 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
return aligned_alloc(new_size, new_alignment, true, p)
}
mode := packed_info.mode
alignment := 1<<packed_info.log2_alignment
switch mode {
case .Alloc, .Alloc_Non_Zeroed:
return aligned_alloc(size, alignment, mode == .Alloc)

View File

@@ -104,6 +104,7 @@ error_string :: proc "contextless" (ferr: Error) -> string {
case .Invalid_Pointer: return "invalid allocator pointer"
case .Invalid_Argument: return "invalid allocator argument"
case .Mode_Not_Implemented: return "allocator mode not implemented"
case .Multiplication_Overflow_On_Requested_Size: return "multiplication overflow on requested allocation size"
}
case Platform_Error:
return _error_string(e)

View File

@@ -493,12 +493,12 @@ free :: proc{free_rawptr, free_cstring}
// Wrap CMark allocator as Odin allocator
@(private)
cmark_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
size, alignment: int,
cmark_allocator_proc :: proc(allocator_data: rawptr, packed_info: runtime.Allocator_Packed_Info,
size: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> (res: []byte, err: runtime.Allocator_Error) {
cmark_alloc := cast(^Allocator)allocator_data
switch mode {
switch packed_info.mode {
case .Alloc, .Alloc_Non_Zeroed:
ptr := cmark_alloc.calloc(1, c.size_t(size))
res = ([^]byte)(ptr)[:size]
@@ -515,8 +515,8 @@ cmark_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mod
return nil, .Mode_Not_Implemented
case .Resize, .Resize_Non_Zeroed:
new_ptr := cmark_alloc.realloc(old_memory, c.size_t(size))
res = transmute([]byte)runtime.Raw_Slice{new_ptr, size}
new_ptr := ([^]byte)(cmark_alloc.realloc(old_memory, c.size_t(size)))
res = new_ptr[:size]
if size > old_size {
runtime.mem_zero(raw_data(res[old_size:]), size - old_size)
}

View File

@@ -1826,10 +1826,9 @@ MemAllocator :: proc "contextless" () -> mem.Allocator {
return mem.Allocator{MemAllocatorProc, nil}
}
MemAllocatorProc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, location := #caller_location) -> (data: []byte, err: mem.Allocator_Error) {
switch mode {
MemAllocatorProc :: proc(allocator_data: rawptr, packed_info: mem.Allocator_Packed_Info,
size: int, old_memory: rawptr, old_size: int, location := #caller_location) -> (data: []byte, err: mem.Allocator_Error) {
switch packed_info.mode {
case .Alloc, .Alloc_Non_Zeroed:
ptr := MemAlloc(c.uint(size))
if ptr == nil {