From 983cac0660b1bbd88226a516b0325ebe7ddedce8 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 11 Oct 2025 22:46:13 -0400 Subject: [PATCH] Bewing cursed stuff... (not sure I'll bother, but I want to see if it works...) --- code2/grime/memory.odin | 129 ++++++++++++++++++++++++++++++---- code2/grime/pkg_mappings.odin | 11 ++- code2/host/host.odin | 2 +- code2/host/pkg_mappings.odin | 2 - 4 files changed, 125 insertions(+), 19 deletions(-) diff --git a/code2/grime/memory.odin b/code2/grime/memory.odin index 03de636..080d98f 100644 --- a/code2/grime/memory.odin +++ b/code2/grime/memory.odin @@ -81,7 +81,7 @@ AllocatorQueryFlag :: enum u64 { Hint_Per_Frame_Temporary, Hint_Debug_Support, } -AllocatorError :: enum byte { +AllocatorError :: enum i32 { None = 0, Out_Of_Memory = 1, Invalid_Pointer = 2, @@ -121,37 +121,69 @@ AllocatorQueryInfo :: struct { left: int, max_alloc: int, min_alloc: int, - continuity_break: b32, + alignment: i32, } AllocatorInfo :: struct { - procedure: AllocatorProc, + _ : struct #raw_union { + procedure: AllocatorProc, + proc_id: AllocatorProcID, + }, data: rawptr, } // #assert(size_of(AllocatorQueryInfo) == size_of(AllocatorProc_Out)) +// Listing of every single allocator (used on hot-reloadable builds) +AllocatorProcID :: enum uintptr { + FArena, + VArena, + CArena, + Pool, + Slab, + Odin_Arena, + // Odin_VArena, +} + +resolve_allocator_proc :: #force_inline proc(procedure: Odin_AllocatorProc) -> AllocatorProc { + when ODIN_DEBUG { + switch (transmute(AllocatorProcID)procedure) { + case .FArena: return nil // farena_allocator_proc + case .VArena: return nil // varena_allocaotr_proc + case .CArena: return nil // carena_allocator_proc + case .Pool: return nil // pool_allocator_proc + case .Slab: return nil // slab_allocator_proc + case .Odin_Arena: return nil // odin_arena_allocator_proc + // case .Odin_VArena: return odin_varena_allocator_proc + } + } + else { + return transmute(AllocatorProc) procedure + } + return nil +} + MEMORY_ALIGNMENT_DEFAULT :: 2 * size_of(rawptr) allocator_query :: proc(ainfo := context.allocator) -> AllocatorQueryInfo { assert(ainfo.procedure != nil) - out: AllocatorQueryInfo; (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Query}, transmute(^AllocatorProc_Out) & out) + out: AllocatorQueryInfo; resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .Query}, transmute(^AllocatorProc_Out) & out) return out } mem_free :: proc(mem: []byte, ainfo := context.allocator) { assert(ainfo.procedure != nil) - (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Free, old_allocation = mem}, & {}) + resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .Free, old_allocation = mem}, & {}) } mem_reset :: proc(ainfo := context.allocator) { assert(ainfo.procedure != nil) - (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Reset}, &{}) + resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .Reset}, &{}) } mem_rewind :: proc(ainfo := context.allocator, save_point: AllocatorSP) { assert(ainfo.procedure != nil) - (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Rewind, save_point = save_point}, & {}) + resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .Rewind, save_point = save_point}, & {}) } mem_save_point :: proc(ainfo := context.allocator) -> AllocatorSP { assert(ainfo.procedure != nil) out: AllocatorProc_Out - (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .SavePoint}, & out) + resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .SavePoint}, & out) return out.save_point } mem_alloc :: proc(size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte { @@ -163,7 +195,7 @@ mem_alloc :: proc(size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: alignment = alignment, } output: AllocatorProc_Out - (cast(AllocatorProc)ainfo.procedure)(input, & output) + resolve_allocator_proc(ainfo.procedure)(input, & output) return output.allocation } mem_grow :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte { @@ -176,7 +208,7 @@ mem_grow :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAU old_allocation = mem, } output: AllocatorProc_Out - (cast(AllocatorProc)ainfo.procedure)(input, & output) + resolve_allocator_proc(ainfo.procedure)(input, & output) return output.allocation } mem_resize :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte { @@ -189,7 +221,7 @@ mem_resize :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEF old_allocation = mem, } output: AllocatorProc_Out - (cast(AllocatorProc)ainfo.procedure)(input, & output) + resolve_allocator_proc(ainfo.procedure)(input, & output) return output.allocation } mem_shrink :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte { @@ -202,7 +234,7 @@ mem_shrink :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEF old_allocation = mem, } output: AllocatorProc_Out - (cast(AllocatorProc)ainfo.procedure)(input, & output) + resolve_allocator_proc(ainfo.procedure)(input, & output) return output.allocation } @@ -215,7 +247,7 @@ alloc_type :: proc($Type: typeid, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no alignment = alignment, } output: AllocatorProc_Out - (cast(AllocatorProc)ainfo.procedure)(input, & output) + resolve_allocator_proc(ainfo.procedure)(input, & output) return transmute(^Type) raw_data(output.allocation) } alloc_slice :: proc($SliceType: typeid / []$Type, num : int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []Type { @@ -227,7 +259,76 @@ alloc_slice :: proc($SliceType: typeid / []$Type, num : int, alignment: int = ME alignment = alignment, } output: AllocatorProc_Out - (cast(AllocatorProc)ainfo.procedure)(input, & output) + resolve_allocator_proc(ainfo.procedure)(input, & output) return transmute([]Type) slice(raw_data(output.allocation), num) } //endregion Allocator Interface + +/* + Ideally we wrap all procedures that go to ideomatic odin with the following pattern: + + Usually we do the following: +``` + import "core:dynlib" + os_lib_load :: dynlib.load_library +``` + Instead: + os_lib_load :: #force_inline proc "contextless" (... same signature as load_library, allocator := ...) { return dynlib.load_library(..., odin_ainfo_wrap(allocator)) } +*/ + +odin_allocator_mode_to_allocator_op :: #force_inline proc "contextless" (mode: Odin_AllocatorMode, size_diff : int) -> AllocatorOp { + switch mode { + case .Alloc: return .Alloc + case .Alloc_Non_Zeroed: return .Alloc_NoZero + case .Free: return .Free + case .Free_All: return .Reset + case .Resize: return size_diff > 0 ? .Grow : .Shrink + case .Resize_Non_Zeroed: return size_diff > 0 ? .Grow_NoZero : .Shrink + case .Query_Features: return .Query + case .Query_Info: return .Query + } + panic_contextless("Impossible path") +} + +odin_allocator_wrap_proc :: proc( + allocator_data : rawptr, + mode : Odin_AllocatorMode, + size : int, + alignment : int, + old_memory : rawptr, + old_size : int, + loc := #caller_location +) -> ( data : []byte, alloc_error : Odin_AllocatorError) +{ + input := AllocatorProc_In { + data = (transmute(^AllocatorInfo)allocator_data).data, + requested_size = size, + alignment = alignment, + old_allocation = slice(transmute([^]byte)old_memory, old_size), + op = odin_allocator_mode_to_allocator_op(mode, size - old_size), + } + output: AllocatorProc_Out + resolve_allocator_proc((transmute(^Odin_Allocator)allocator_data).procedure)(input, & output) + + #partial switch mode { + case .Query_Features: + debug_trap() // TODO(Ed): Finish this... + return nil, nil + case .Query_Info: + info := (^Odin_AllocatorQueryInfo)(old_memory) + if info != nil && info.pointer != nil { + info.size = output.left + info.alignment = cast(int) (transmute(AllocatorQueryInfo)output).alignment + return slice(transmute(^byte)info, size_of(info^) ), nil + } + return nil, nil + } + return output.allocation, cast(Odin_AllocatorError)output.error +} + +odin_ainfo_wrap :: #force_inline proc(ainfo := context.allocator) -> Odin_Allocator { + @(thread_local) + cursed_allocator_wrap_ref : Odin_Allocator + cursed_allocator_wrap_ref = {ainfo.procedure, ainfo.data} + return {odin_allocator_wrap_proc, & cursed_allocator_wrap_ref} +} diff --git a/code2/grime/pkg_mappings.odin b/code2/grime/pkg_mappings.odin index 141ee42..948d8de 100644 --- a/code2/grime/pkg_mappings.odin +++ b/code2/grime/pkg_mappings.odin @@ -21,17 +21,24 @@ import "base:runtime" import fmt_io "core:fmt" str_pfmt_out :: fmt_io.printf - str_pfmt_tmp :: fmt_io.tprintf + str_pfmt_tmp :: #force_inline proc(fmt: string, args: ..any, newline := false) -> string { context.temp_allocator = odin_ainfo_wrap(context.temp_allocator); return fmt_io.tprintf(fmt, ..args, newline = newline) } str_pfmt :: fmt_io.aprintf // Decided to make aprintf the default. (It will always be the default allocator) str_pfmt_builder :: fmt_io.sbprintf str_pfmt_buffer :: fmt_io.bprintf str_pfmt_file_ln :: fmt_io.fprintln - str_tmp_from_any :: fmt_io.tprint + str_tmp_from_any :: fmt_io.tprint import "core:log" Default_File_Logger_Opts :: log.Default_File_Logger_Opts Logger_Full_Timestamp_Opts :: log.Full_Timestamp_Opts +import "core:mem" + Odin_AllocatorMode :: mem.Allocator_Mode + Odin_AllocatorProc :: mem.Allocator_Proc + Odin_Allocator :: mem.Allocator + Odin_AllocatorQueryInfo :: mem.Allocator_Query_Info + Odin_AllocatorError :: mem.Allocator_Error + import core_os "core:os" FS_Open_Readonly :: core_os.O_RDONLY FS_Open_Writeonly :: core_os.O_WRONLY diff --git a/code2/host/host.odin b/code2/host/host.odin index f22367a..565c1be 100644 --- a/code2/host/host.odin +++ b/code2/host/host.odin @@ -22,7 +22,7 @@ main :: proc() { // TODO(Ed): Change this host_scratch: mem.Arena; mem.arena_init(& host_scratch, host_memory.host_scratch[:]) - context.allocator = mem.arena_allocator(& host_scratch) + context.allocator = mem.arena_allocator(& host_scratch) context.temp_allocator = context.allocator thread_memory.index = .Master_Prepper diff --git a/code2/host/pkg_mappings.odin b/code2/host/pkg_mappings.odin index cf691c0..7f2ecf6 100644 --- a/code2/host/pkg_mappings.odin +++ b/code2/host/pkg_mappings.odin @@ -48,5 +48,3 @@ Kilo :: 1024 Mega :: Kilo * 1024 Giga :: Mega * 1024 Tera :: Giga * 1024 - -