diff --git a/code2/grime/allocator_interface.odin b/code2/grime/allocator_interface.odin index b2dbfb2..26b3f0a 100644 --- a/code2/grime/allocator_interface.odin +++ b/code2/grime/allocator_interface.odin @@ -177,9 +177,6 @@ odin_allocator_mode_to_allocator_op :: #force_inline proc "contextless" (mode: O panic_contextless("Impossible path") } -// TODO(Ed): Change to DEFAULT_ALIGNMENT -MEMORY_ALIGNMENT_DEFAULT :: 2 * size_of(rawptr) - allocatorinfo :: #force_inline proc(ainfo := context.allocator) -> AllocatorInfo { return transmute(AllocatorInfo) ainfo } allocator :: #force_inline proc(ainfo: AllocatorInfo) -> Odin_Allocator { return transmute(Odin_Allocator) ainfo } @@ -202,11 +199,10 @@ mem_rewind :: proc(ainfo := context.allocator, save_point: AllocatorSP, loc := # } mem_save_point :: proc(ainfo := context.allocator, loc := #caller_location) -> AllocatorSP { assert(ainfo.procedure != nil) - out: AllocatorProc_Out - resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .SavePoint, loc = loc}, & out) + out: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .SavePoint, loc = loc}, & out) return out.save_point } -mem_alloc :: proc(size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo: $Type = context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) { +mem_alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo: $Type = context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) { assert(ainfo.procedure != nil) input := AllocatorProc_In { data = ainfo.data, @@ -215,11 +211,10 @@ mem_alloc :: proc(size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: alignment = alignment, loc = loc, } - output: AllocatorProc_Out - resolve_allocator_proc(ainfo.procedure)(input, & output) + output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output) return output.allocation, output.error } -mem_grow :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) { +mem_grow :: proc(mem: []byte, size: int, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) { assert(ainfo.procedure != nil) input := AllocatorProc_In { data = ainfo.data, @@ -229,11 +224,10 @@ mem_grow :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAU old_allocation = mem, loc = loc, } - output: AllocatorProc_Out - resolve_allocator_proc(ainfo.procedure)(input, & output) + output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output) return output.allocation, output.error } -mem_resize :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) { +mem_resize :: proc(mem: []byte, size: int, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) { assert(ainfo.procedure != nil) input := AllocatorProc_In { data = ainfo.data, @@ -243,11 +237,10 @@ mem_resize :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEF old_allocation = mem, loc = loc, } - output: AllocatorProc_Out - resolve_allocator_proc(ainfo.procedure)(input, & output) + output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output) return output.allocation, output.error } -mem_shrink :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) { +mem_shrink :: proc(mem: []byte, size: int, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) { assert(ainfo.procedure != nil) input := AllocatorProc_In { data = ainfo.data, @@ -257,12 +250,11 @@ mem_shrink :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEF old_allocation = mem, loc = loc, } - output: AllocatorProc_Out - resolve_allocator_proc(ainfo.procedure)(input, & output) + output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output) return output.allocation, output.error } -alloc_type :: proc($Type: typeid, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> (^Type, AllocatorError) { +alloc_type :: proc($Type: typeid, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> (^Type, AllocatorError) { assert(ainfo.procedure != nil) input := AllocatorProc_In { data = ainfo.data, @@ -271,11 +263,10 @@ alloc_type :: proc($Type: typeid, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no alignment = alignment, loc = loc, } - output: AllocatorProc_Out - resolve_allocator_proc(ainfo.procedure)(input, & output) + output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output) return transmute(^Type) raw_data(output.allocation), output.error } -alloc_slice :: proc($SliceType: typeid / []$Type, num: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]Type, AllocatorError) { +alloc_slice :: proc($SliceType: typeid / []$Type, num: int, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]Type, AllocatorError) { assert(ainfo.procedure != nil) input := AllocatorProc_In { data = ainfo.data, @@ -284,7 +275,6 @@ alloc_slice :: proc($SliceType: typeid / []$Type, num: int, alignment: int = MEM alignment = alignment, loc = loc, } - output: AllocatorProc_Out - resolve_allocator_proc(ainfo.procedure)(input, & output) + output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output) return transmute([]Type) slice(raw_data(output.allocation), num), output.error } diff --git a/code2/grime/dynamic_array.odin b/code2/grime/dynamic_array.odin index 33076cd..2074901 100644 --- a/code2/grime/dynamic_array.odin +++ b/code2/grime/dynamic_array.odin @@ -79,7 +79,7 @@ array_set_capacity :: proc( self : ^Array( $ Type ), new_capacity: int) -> Alloc header_size :: size_of(ArrayHeader(Type)) new_size := header_size + new_capacity * size_of(Type) old_size := header_size + self.capacity * size_of(Type) - new_mem, result_code := mem_resize( slice(transmute(^u8)self.header, old_size), new_size, MEMORY_ALIGNMENT_DEFAULT, ainfo = self.backing ) + new_mem, result_code := mem_resize( slice(transmute(^u8)self.header, old_size), new_size, DEFAULT_ALIGNMENT, ainfo = self.backing ) if ensure( result_code != AllocatorError.None, "Failed to allocate for new array capacity" ) { log_print( "Failed to allocate for new array capacity", level = LoggerLevel.Warning ) return result_code diff --git a/code2/grime/fixed_arena.odin b/code2/grime/fixed_arena.odin index b31b54f..b399268 100644 --- a/code2/grime/fixed_arena.odin +++ b/code2/grime/fixed_arena.odin @@ -17,7 +17,7 @@ farena_init :: proc "contextless" (arena: ^FArena, backing: []byte) { arena.used = 0 } @require_results -farena_push :: proc "contextless" (arena: ^FArena, $Type: typeid, amount: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, loc := #caller_location) -> ([]Type, AllocatorError) { +farena_push :: proc "contextless" (arena: ^FArena, $Type: typeid, amount: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> ([]Type, AllocatorError) { assert_contextless(arena != nil) if amount == 0 { return {}, .None @@ -32,7 +32,7 @@ farena_push :: proc "contextless" (arena: ^FArena, $Type: typeid, amount: int, a return slice(cursor(arena.mem)[arena.used:], amount), .None } @require_results -farena_grow :: proc "contextless" (arena: ^FArena, old_allocation: []byte, requested_size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, should_zero: bool = true, loc := #caller_location) -> (allocation: []byte, err: AllocatorError) { +farena_grow :: proc "contextless" (arena: ^FArena, old_allocation: []byte, requested_size: int, alignment: int = DEFAULT_ALIGNMENT, should_zero: bool = true, loc := #caller_location) -> (allocation: []byte, err: AllocatorError) { assert_contextless(arena != nil) if len(old_allocation) == 0 { return {}, .Invalid_Argument @@ -58,7 +58,7 @@ farena_grow :: proc "contextless" (arena: ^FArena, old_allocation: []byte, reque return } @require_results -farena_shirnk :: proc "contextless" (arena: ^FArena, old_allocation: []byte, requested_size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, loc := #caller_location) -> (allocation: []byte, err: AllocatorError) { +farena_shirnk :: proc "contextless" (arena: ^FArena, old_allocation: []byte, requested_size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> (allocation: []byte, err: AllocatorError) { assert_contextless(arena != nil) if len(old_allocation) == 0 { return {}, .Invalid_Argument @@ -70,7 +70,7 @@ farena_shirnk :: proc "contextless" (arena: ^FArena, old_allocation: []byte, req return old_allocation[:requested_size], .None } // Calculate shrinkage - aligned_original := align_pow2(len(old_allocation), MEMORY_ALIGNMENT_DEFAULT) + aligned_original := align_pow2(len(old_allocation), DEFAULT_ALIGNMENT) aligned_new := align_pow2(requested_size, alignment) arena.used -= (aligned_original - aligned_new) return old_allocation[:requested_size], .None @@ -162,7 +162,7 @@ farena_odin_allocator_proc :: proc( info := (^Odin_AllocatorQueryInfo)(old_memory) info.pointer = transmute(rawptr) farena_save(arena^).slot info.size = len(arena.mem) - arena.used - info.alignment = MEMORY_ALIGNMENT_DEFAULT + info.alignment = DEFAULT_ALIGNMENT return to_bytes(info), nil } panic_contextless("Impossible path") diff --git a/code2/grime/key_table_inear.odin b/code2/grime/key_table_inear.odin index bee444a..ab99ef1 100644 --- a/code2/grime/key_table_inear.odin +++ b/code2/grime/key_table_inear.odin @@ -31,7 +31,7 @@ ktl_populate_slice_a2_str :: #force_inline proc(kt: ^[]KTL_Slot(string), backing raw_bytes, error := mem_alloc(size_of(KTL_Slot(string)) * len(values), ainfo = backing); assert(error == .None); kt^ = slice( transmute([^]KTL_Slot(string)) cursor(raw_bytes), len(raw_bytes) / size_of(KTL_Slot(string)) ) for id in 0 ..< len(values) { - mem_copy_non_overlapping(& kt[id].value, & values[id][1], size_of(string)) + mem_copy(& kt[id].value, & values[id][1], size_of(string)) hash64_fnv1a(& kt[id].key, transmute([]byte) values[id][0]) } } diff --git a/code2/grime/pkg_mappings.odin b/code2/grime/pkg_mappings.odin index a74af1f..70df421 100644 --- a/code2/grime/pkg_mappings.odin +++ b/code2/grime/pkg_mappings.odin @@ -11,9 +11,9 @@ import "base:intrinsics" // mem_copy :: intrinsics.mem_copy_non_overlapping // mem_copy_overlapping :: intrinsics.mem_copy -mem_zero :: #force_inline proc "contextless" (data: rawptr, len: int) { intrinsics.mem_zero (data, len) } -mem_copy_non_overlapping :: #force_inline proc "contextless" (dst, src: rawptr, len: int) { intrinsics.mem_copy_non_overlapping(dst, src, len) } -mem_copy :: #force_inline proc "contextless" (dst, src: rawptr, len: int) { intrinsics.mem_copy (dst, src, len) } +mem_zero :: #force_inline proc "contextless" (data: rawptr, len: int) { intrinsics.mem_zero (data, len) } +mem_copy :: #force_inline proc "contextless" (dst, src: rawptr, len: int) { intrinsics.mem_copy_non_overlapping(dst, src, len) } +mem_copy_overlapping :: #force_inline proc "contextless" (dst, src: rawptr, len: int) { intrinsics.mem_copy (dst, src, len) } import "base:runtime" Assertion_Failure_Proc :: runtime.Assertion_Failure_Proc @@ -40,6 +40,9 @@ import "core:log" Logger_Full_Timestamp_Opts :: log.Full_Timestamp_Opts import "core:mem" + DEFAULT_ALIGNMENT :: mem.DEFAULT_ALIGNMENT + DEFAULT_PAGE_SIZE :: mem.DEFAULT_PAGE_SIZE + Odin_Allocator :: mem.Allocator Odin_AllocatorError :: mem.Allocator_Error Odin_AllocatorQueryInfo :: mem.Allocator_Query_Info @@ -141,8 +144,8 @@ copy :: proc { mem_copy, slice_copy, } -copy_non_overlapping :: proc { - mem_copy_non_overlapping, +copy_overlapping :: proc { + mem_copy_overlapping, slice_copy_overlapping, } fill :: proc { diff --git a/code2/grime/virtual_arena.odin b/code2/grime/virtual_arena.odin index 17379ff..1f207b3 100644 --- a/code2/grime/virtual_arena.odin +++ b/code2/grime/virtual_arena.odin @@ -22,7 +22,6 @@ VArenaFlags :: bit_set[VArenaFlag; u32] VArenaFlag :: enum u32 { No_Large_Pages, } - VArena :: struct { using vmem: VirtualMemoryRegion, commit_size: int, @@ -46,13 +45,13 @@ varena_make :: proc(to_reserve, commit_size: int, base_address: uintptr, flags: } arena = transmute(^VArena) vmem.base_address; arena.vmem = vmem - arena.commit_used = align_pow2(size_of(arena), MEMORY_ALIGNMENT_DEFAULT) + arena.commit_used = align_pow2(size_of(arena), DEFAULT_ALIGNMENT) arena.flags = flags return } varena_alloc :: proc(self: ^VArena, - size: int, - alignment: int = MEMORY_ALIGNMENT_DEFAULT, + size: int, + alignment: int = DEFAULT_ALIGNMENT, zero_memory := true, location := #caller_location ) -> (data: []byte, alloc_error: AllocatorError) @@ -104,11 +103,11 @@ varena_alloc :: proc(self: ^VArena, } return } -varena_grow :: #force_inline proc(self: ^VArena, old_memory: []byte, requested_size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, should_zero := true, loc := #caller_location +varena_grow :: #force_inline proc(self: ^VArena, old_memory: []byte, requested_size: int, alignment: int = DEFAULT_ALIGNMENT, zero_memory := true, loc := #caller_location ) -> (data: []byte, error: AllocatorError) { if ensure(old_memory == nil, "Growing without old_memory?") { - data, error = varena_alloc(self, requested_size, alignment, should_zero, loc) + data, error = varena_alloc(self, requested_size, alignment, zero_memory, loc) return } if ensure(requested_size == len(old_memory), "Requested grow when none needed") { @@ -137,18 +136,18 @@ varena_grow :: #force_inline proc(self: ^VArena, old_memory: []byte, requested_s { // Give it new memory and copy the old over. Old memory is unrecoverable until clear. new_region : []byte - new_region, error = varena_alloc( self, requested_size, alignment, should_zero, loc ) + new_region, error = varena_alloc( self, requested_size, alignment, zero_memory, loc ) if ensure(new_region == nil || error != .None, "Failed to grab new region") { data = old_memory return } - copy_non_overlapping( cursor(new_region), cursor(old_memory), len(old_memory) ) + copy( cursor(new_region), cursor(old_memory), len(old_memory) ) data = new_region // log_print_fmt("varena resize (new): old: %p %v new: %p %v", old_memory, old_size, (& data[0]), size) return } new_region : []byte - new_region, error = varena_alloc( self, requested_size - len(old_memory), alignment, should_zero, loc) + new_region, error = varena_alloc( self, requested_size - len(old_memory), alignment, zero_memory, loc) if ensure(new_region == nil || error != .None, "Failed to grab new region") { data = old_memory return @@ -243,7 +242,7 @@ varena_odin_allocator_proc :: proc( info := (^Odin_AllocatorQueryInfo)(old_memory) info.pointer = transmute(rawptr) varena_save(arena).slot info.size = cast(int) arena.reserved - info.alignment = MEMORY_ALIGNMENT_DEFAULT + info.alignment = DEFAULT_ALIGNMENT return to_bytes(info), nil } return @@ -263,12 +262,12 @@ else { varena_allocator :: #force_inline proc "contextless" (arena: ^VArena) -> Odin_Allocator { return transmute(Odin_Allocator) AllocatorInfo{procedure = varena_allocator_proc, data = arena} } } -varena_push_item :: #force_inline proc(va: ^VArena, $Type: typeid, alignment: int = MEMORY_ALIGNMENT_DEFAULT, should_zero := true, location := #caller_location +varena_push_item :: #force_inline proc(va: ^VArena, $Type: typeid, alignment: int = DEFAULT_ALIGNMENT, should_zero := true, location := #caller_location ) -> (^Type, AllocatorError) { raw, error := varena_alloc(va, size_of(Type), alignment, should_zero, location) return transmute(^Type) cursor(raw), error } -varena_push_slice :: #force_inline proc(va: ^VArena, $Type: typeid, amount: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, should_zero := true, location := #caller_location +varena_push_slice :: #force_inline proc(va: ^VArena, $Type: typeid, amount: int, alignment: int = DEFAULT_ALIGNMENT, should_zero := true, location := #caller_location ) -> ([]Type, AllocatorError) { raw, error := varena_alloc(va, size_of(Type) * amount, alignment, should_zero, location) return slice(transmute([^]Type) cursor(raw), len(raw) / size_of(Type)), error diff --git a/code2/grime/virtual_chained_arena.odin b/code2/grime/virtual_chained_arena.odin index 893c2af..610a33a 100644 --- a/code2/grime/virtual_chained_arena.odin +++ b/code2/grime/virtual_chained_arena.odin @@ -19,13 +19,11 @@ Arena :: struct { } arena_make :: proc(reserve_size : int = Mega * 64, commit_size : int = Mega * 64, base_addr: uintptr = 0, flags: ArenaFlags = {}) -> ^Arena { - header_size := align_pow2(size_of(Arena), MEMORY_ALIGNMENT_DEFAULT) + header_size := align_pow2(size_of(Arena), DEFAULT_ALIGNMENT) current, error := varena_make(reserve_size, commit_size, base_addr, transmute(VArenaFlags) flags) assert(error == .None) - assert(current != nil) arena: ^Arena; arena, error = varena_push_item(current, Arena, 1) assert(error == .None) - assert(arena != nil) arena^ = Arena { backing = current, prev = nil, @@ -36,7 +34,7 @@ arena_make :: proc(reserve_size : int = Mega * 64, commit_size : int = Mega * 64 } return arena } -arena_alloc :: proc(arena: ^Arena, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT) -> []byte { +arena_alloc :: proc(arena: ^Arena, size: int, alignment: int = DEFAULT_ALIGNMENT, should_zero := true) -> []byte { assert(arena != nil) active := arena.current size_requested := size @@ -53,13 +51,40 @@ arena_alloc :: proc(arena: ^Arena, size: int, alignment: int = MEMORY_ALIGNMENT_ active = arena.current } result_ptr := transmute([^]byte) (uintptr(active) + uintptr(pos_pre)) - vresult, error := varena_alloc(active.backing, size_aligned, alignment) + vresult, error := varena_alloc(active.backing, size_aligned, alignment, should_zero) assert(error == .None) - slice_assert(vresult) - assert(raw_data(vresult) == result_ptr) + assert(cursor(vresult) == result_ptr) active.pos = pos_pst return slice(result_ptr, size) } +arena_grow :: proc(arena: ^Arena, old_allocation: []byte, requested_size: int, alignment: int = DEFAULT_ALIGNMENT, zero_memory := true) -> (allocation: []byte) { + active := arena.current + if len(old_allocation) == 0 { allocation = {}; return } + alloc_end := end(old_allocation) + arena_end := transmute([^]byte) (uintptr(active) + uintptr(active.pos)) + if alloc_end == arena_end + { + // Can grow in place + grow_amount := requested_size - len(old_allocation) + aligned_grow := align_pow2(grow_amount, alignment) + if active.pos + aligned_grow <= cast(int) active.backing.reserved + { + vresult, error := varena_alloc(active.backing, aligned_grow, alignment, zero_memory); + assert(error == .None) + if len(vresult) > 0 { + active.pos += aligned_grow + allocation = slice(cursor(old_allocation), requested_size) + return + } + } + } + // Can't grow in place, allocate new + allocation = arena_alloc(arena, requested_size, alignment, false) + if len(allocation) == 0 { allocation = {}; return } + copy(allocation, old_allocation) + zero(cursor(allocation)[len(old_allocation):], (requested_size - len(old_allocation)) * int(zero_memory)) + return +} arena_release :: proc(arena: ^Arena) { assert(arena != nil) curr := arena.current @@ -75,7 +100,7 @@ arena_reset :: proc(arena: ^Arena) { arena_rewind :: proc(arena: ^Arena, save_point: AllocatorSP) { assert(arena != nil) assert(save_point.type_sig == arena_allocator_proc) - header_size := align_pow2(size_of(Arena), MEMORY_ALIGNMENT_DEFAULT) + header_size := align_pow2(size_of(Arena), DEFAULT_ALIGNMENT) curr := arena.current big_pos := max(header_size, save_point.slot) // Release arenas that are beyond the save point @@ -85,8 +110,7 @@ arena_rewind :: proc(arena: ^Arena, save_point: AllocatorSP) { curr = prev } arena.current = curr - new_pos := big_pos - curr.base_pos - assert(new_pos <= curr.pos) + new_pos := big_pos - curr.base_pos; assert(new_pos <= curr.pos) curr.pos = new_pos varena_rewind(curr.backing, { type_sig = varena_allocator_proc, slot = curr.pos + size_of(VArena) }) } diff --git a/code2/grime/virtual_memory.odin b/code2/grime/virtual_memory.odin index 87f0a4d..ff0355a 100644 --- a/code2/grime/virtual_memory.odin +++ b/code2/grime/virtual_memory.odin @@ -32,7 +32,7 @@ virtual_reserve_remaining :: proc "contextless" ( using vmem : VirtualMemoryRegi @(require_results) virtual_commit :: proc "contextless" ( using vmem : VirtualMemoryRegion, size : uint ) -> ( alloc_error : AllocatorError ) { - if size < committed { + if size < committed { return .None } diff --git a/code2/grime/virtual_pool.odin b/code2/grime/virtual_pool.odin index 2bad9c4..48f0ec7 100644 --- a/code2/grime/virtual_pool.odin +++ b/code2/grime/virtual_pool.odin @@ -24,5 +24,3 @@ pool_make :: proc() -> (pool: VPool, error: AllocatorError) panic("not implemented") // return } - -