diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index 54004d333..b5788c8a8 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -243,13 +243,11 @@ default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, a return alloc_bytes(new_size, alignment, allocator, loc) } - if new_size == 0 { - err := free_bytes(old_data, allocator, loc) - return nil, err - } - if new_size == old_size { - return old_data, .None + return old_data, nil + } + if new_size == 0 { + return nil, free_bytes(old_data, allocator, loc) } new_memory, err := alloc_bytes(new_size, alignment, allocator, loc) @@ -258,6 +256,9 @@ default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, a } runtime.copy(new_memory, old_data) - free_bytes(old_data, allocator, loc) + err1 := free_bytes(old_data, allocator, loc) + if err == nil { + err = err1 + } return new_memory, err } diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin new file mode 100644 index 000000000..45426eddc --- /dev/null +++ b/core/mem/virtual/arena.odin @@ -0,0 +1,300 @@ +package mem_virtual + +import "core:mem" + +Arena_Kind :: enum uint { + Growing = 0, // chained memory blocks (singly linked list) + Static = 1, // fixed reservation sized +} + +Arena :: struct { + kind: Arena_Kind, + curr_block: ^Memory_Block, + total_used: uint, + total_reserved: uint, + minimum_block_size: uint, + temp_count: uint, +} + + +// 1 MiB should be enough to start with +DEFAULT_ARENA_STATIC_COMMIT_SIZE :: 1<<20 +DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: DEFAULT_ARENA_STATIC_COMMIT_SIZE + +// 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default +DEFAULT_ARENA_STATIC_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27 + + + +@(require_results) +arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) { + arena.kind = .Growing + arena.curr_block = memory_block_alloc(0, reserved, {}) or_return + arena.total_used = 0 + arena.total_reserved = arena.curr_block.reserved + return +} + + +@(require_results) +arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) { + arena.kind = .Static + arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return + arena.total_used = 0 + arena.total_reserved = arena.curr_block.reserved + return +} + +@(require_results) +arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { + assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc) + + size := size + if size == 0 { + return nil, nil + } + + switch arena.kind { + case .Growing: + if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved { + size = mem.align_forward_uint(size, alignment) + if arena.minimum_block_size == 0 { + arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE + } + + block_size := max(size, arena.minimum_block_size) + + new_block := memory_block_alloc(size, block_size, {}) or_return + new_block.prev = arena.curr_block + arena.curr_block = new_block + arena.total_reserved += new_block.reserved + } + + prev_used := arena.curr_block.used + data, err = alloc_from_memory_block(arena.curr_block, size, alignment) + arena.total_used += arena.curr_block.used - prev_used + case .Static: + if arena.curr_block == nil { + if arena.minimum_block_size == 0 { + arena.minimum_block_size = DEFAULT_ARENA_STATIC_RESERVE_SIZE + } + arena_init_static(arena=arena, reserved=arena.minimum_block_size, commit_size=DEFAULT_ARENA_STATIC_COMMIT_SIZE) or_return + } + data, err = alloc_from_memory_block(arena.curr_block, size, alignment) + arena.total_used = arena.curr_block.used + } + return +} + +arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool { + if arena.curr_block != nil { + assert(arena.kind == .Static, "expected a .Static arena", loc) + + prev_pos := arena.curr_block.used + arena.curr_block.used = clamp(pos, 0, arena.curr_block.reserved) + + if prev_pos < pos { + mem.zero_slice(arena.curr_block.base[arena.curr_block.used:][:pos-prev_pos]) + } + arena.total_used = arena.curr_block.used + return true + } else if pos == 0 { + arena.total_used = 0 + return true + } + return false +} + +arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) { + if free_block := arena.curr_block; free_block != nil { + assert(arena.kind == .Growing, "expected a .Growing arena", loc) + arena.curr_block = free_block.prev + memory_block_dealloc(free_block) + } +} + +arena_free_all :: proc(arena: ^Arena) { + switch arena.kind { + case .Growing: + for arena.curr_block != nil { + arena_growing_free_last_memory_block(arena) + } + arena.total_reserved = 0 + case .Static: + arena_static_reset_to(arena, 0) + } + arena.total_used = 0 +} + +arena_destroy :: proc(arena: ^Arena) { + arena_free_all(arena) + memory_block_dealloc(arena.curr_block) + arena.curr_block = nil + arena.total_used = 0 + arena.total_reserved = 0 + arena.temp_count = 0 +} + +arena_growing_bootstrap_new :: proc{ + arena_growing_bootstrap_new_by_offset, + arena_growing_bootstrap_new_by_name, +} + +arena_static_bootstrap_new :: proc{ + arena_static_bootstrap_new_by_offset, + arena_static_bootstrap_new_by_name, +} + +@(require_results) +arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { + bootstrap: Arena + bootstrap.kind = .Growing + bootstrap.minimum_block_size = minimum_block_size + + data := arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return + + ptr = (^T)(raw_data(data)) + + (^Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap + + return +} + +@(require_results) +arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { + return arena_growing_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size) +} + +@(require_results) +arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) { + bootstrap: Arena + bootstrap.kind = .Static + bootstrap.minimum_block_size = reserved + + data := arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return + + ptr = (^T)(raw_data(data)) + + (^Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap + + return +} + +@(require_results) +arena_static_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) { + return arena_static_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved) +} + + +@(require_results) +arena_allocator :: proc(arena: ^Arena) -> mem.Allocator { + return mem.Allocator{arena_allocator_proc, arena} +} + +arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, + size, alignment: 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) + old_size := uint(old_size) + + switch mode { + case .Alloc: + return arena_alloc(arena, size, alignment) + case .Free: + err = .Mode_Not_Implemented + case .Free_All: + arena_free_all(arena) + case .Resize: + old_data := ([^]byte)(old_memory) + + switch { + case old_data == nil: + return arena_alloc(arena, size, alignment) + case size == old_size: + // return old memory + data = old_data[:size] + return + 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 + } + + new_memory := arena_alloc(arena, size, alignment) or_return + if new_memory == nil { + return + } + copy(new_memory, old_data[:old_size]) + return new_memory, nil + case .Query_Features: + set := (^mem.Allocator_Mode_Set)(old_memory) + if set != nil { + set^ = {.Alloc, .Free_All, .Resize, .Query_Features} + } + case .Query_Info: + err = .Mode_Not_Implemented + } + + return +} + + + + +Arena_Temp :: struct { + arena: ^Arena, + block: ^Memory_Block, + used: uint, +} + +@(require_results) +arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) { + assert(arena != nil, "nil arena", loc) + temp.arena = arena + temp.block = arena.curr_block + if arena.curr_block != nil { + temp.used = arena.curr_block.used + } + arena.temp_count += 1 + return +} + +arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) { + assert(temp.arena != nil, "nil arena", loc) + arena := temp.arena + + memory_block_found := false + for block := arena.curr_block; block != nil; block = block.prev { + if block == temp.block { + memory_block_found = true + break + } + } + if !memory_block_found { + assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc) + } + + for arena.curr_block != temp.block { + arena_growing_free_last_memory_block(arena) + } + + if block := arena.curr_block; block != nil { + assert(block.used >= temp.used, "out of order use of arena_temp_end", loc) + amount_to_zero := min(block.used-temp.used, block.reserved-block.used) + mem.zero_slice(block.base[temp.used:][:amount_to_zero]) + block.used = temp.used + } + + assert(arena.temp_count > 0, "double-use of arena_temp_end", loc) + arena.temp_count -= 1 +} + +arena_check_temp :: proc(arena: ^Arena, loc := #caller_location) { + assert(arena.temp_count == 0, "Arena_Temp not been ended", loc) +} diff --git a/core/mem/virtual/arena_util.odin b/core/mem/virtual/arena_util.odin deleted file mode 100644 index 0e152db7a..000000000 --- a/core/mem/virtual/arena_util.odin +++ /dev/null @@ -1,41 +0,0 @@ -package mem_virtual - -arena_init :: proc{ - static_arena_init, - growing_arena_init, -} - -arena_temp_begin :: proc{ - static_arena_temp_begin, - growing_arena_temp_begin, -} - -arena_temp_end :: proc{ - static_arena_temp_end, - growing_arena_temp_end, -} - -arena_check_temp :: proc{ - static_arena_check_temp, - growing_arena_check_temp, -} - -arena_allocator :: proc{ - static_arena_allocator, - growing_arena_allocator, -} - -arena_alloc :: proc{ - static_arena_alloc, - growing_arena_alloc, -} - -arena_free_all :: proc{ - static_arena_free_all, - growing_arena_free_all, -} - -arena_destroy :: proc{ - static_arena_destroy, - growing_arena_destroy, -} \ No newline at end of file diff --git a/core/mem/virtual/growing_arena.odin b/core/mem/virtual/growing_arena.odin deleted file mode 100644 index 44d56866e..000000000 --- a/core/mem/virtual/growing_arena.odin +++ /dev/null @@ -1,170 +0,0 @@ -package mem_virtual - -import "core:mem" - -Growing_Arena :: struct { - curr_block: ^Memory_Block, - total_used: uint, - total_reserved: uint, - - minimum_block_size: uint, - temp_count: int, -} - -DEFAULT_MINIMUM_BLOCK_SIZE :: 1<<20 // 1 MiB should be enough - -growing_arena_init :: proc(arena: ^Growing_Arena, reserved: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) { - arena.curr_block = memory_block_alloc(0, reserved, {}) or_return - arena.total_used = 0 - arena.total_reserved = arena.curr_block.reserved - return -} - -growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: Allocator_Error) { - align_forward_offset :: proc "contextless" (arena: ^Growing_Arena, alignment: int) -> uint #no_bounds_check { - alignment_offset := uint(0) - ptr := uintptr(arena.curr_block.base[arena.curr_block.used:]) - mask := uintptr(alignment-1) - if ptr & mask != 0 { - alignment_offset = uint(alignment) - uint(ptr & mask) - } - return alignment_offset - } - - assert(mem.is_power_of_two(uintptr(alignment))) - - size := uint(0) - if arena.curr_block != nil { - size = uint(min_size) + align_forward_offset(arena, alignment) - } - - if arena.curr_block == nil || arena.curr_block.used + size > arena.curr_block.reserved { - size = uint(mem.align_forward_int(min_size, alignment)) - arena.minimum_block_size = max(DEFAULT_MINIMUM_BLOCK_SIZE, arena.minimum_block_size) - - block_size := max(size, arena.minimum_block_size) - - new_block := memory_block_alloc(size, block_size, {}) or_return - new_block.prev = arena.curr_block - arena.curr_block = new_block - arena.total_reserved += new_block.reserved - } - - - data, err = alloc_from_memory_block(arena.curr_block, int(size), alignment) - if err == nil { - arena.total_used += size - } - return -} - -growing_arena_free_last_memory_block :: proc(arena: ^Growing_Arena) { - free_block := arena.curr_block - arena.curr_block = free_block.prev - memory_block_dealloc(free_block) -} - -growing_arena_free_all :: proc(arena: ^Growing_Arena) { - for arena.curr_block != nil { - growing_arena_free_last_memory_block(arena) - } - arena.total_used = 0 - arena.total_reserved = 0 -} - -growing_arena_destroy :: proc(arena: ^Growing_Arena) { - growing_arena_free_all(arena) -} - -growing_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { bootstrap: Growing_Arena - bootstrap.minimum_block_size = minimum_block_size - - data := growing_arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return - - ptr = (^T)(raw_data(data)) - - (^Growing_Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap - - return -} - -growing_arena_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { - return growing_arena_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size) -} -growing_arena_bootstrap_new :: proc{ - growing_arena_bootstrap_new_by_offset, - growing_arena_bootstrap_new_by_name, -} - -growing_arena_allocator :: proc(arena: ^Growing_Arena) -> mem.Allocator { - return mem.Allocator{growing_arena_allocator_proc, arena} -} - -growing_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, - location := #caller_location) -> (data: []byte, err: Allocator_Error) { - arena := (^Growing_Arena)(allocator_data) - - switch mode { - case .Alloc: - return growing_arena_alloc(arena, size, alignment) - case .Free: - err = .Mode_Not_Implemented - return - case .Free_All: - growing_arena_free_all(arena) - return - case .Resize: - return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, growing_arena_allocator(arena), location) - - case .Query_Features, .Query_Info: - err = .Mode_Not_Implemented - return - } - - err = .Mode_Not_Implemented - return -} - -Growing_Arena_Temp :: struct { - arena: ^Growing_Arena, - block: ^Memory_Block, - used: uint, -} - -growing_arena_temp_begin :: proc(arena: ^Growing_Arena) -> (temp: Growing_Arena_Temp) { - temp.arena = arena - temp.block = arena.curr_block - if arena.curr_block != nil { - temp.used = arena.curr_block.used - } - arena.temp_count += 1 - return -} - -growing_arena_temp_end :: proc(temp: Growing_Arena_Temp, loc := #caller_location) { - assert(temp.arena != nil, "nil arena", loc) - arena := temp.arena - - for arena.curr_block != temp.block { - growing_arena_free_last_memory_block(arena) - } - - if block := arena.curr_block; block != nil { - assert(block.used >= temp.used, "out of order use of growing_arena_temp_end", loc) - amount_to_zero := min(block.used-temp.used, block.reserved-block.used) - mem.zero_slice(block.base[temp.used:][:amount_to_zero]) - block.used = temp.used - } - - assert(arena.temp_count > 0, "double-use of growing_arena_temp_end", loc) - arena.temp_count -= 1 -} - -growing_arena_check_temp :: proc(arena: ^Growing_Arena, loc := #caller_location) { - assert(arena.temp_count == 0, "Growing_Arena_Temp not been ended", loc) -} - - - diff --git a/core/mem/virtual/static_arena.odin b/core/mem/virtual/static_arena.odin deleted file mode 100644 index 7e8a62f4a..000000000 --- a/core/mem/virtual/static_arena.odin +++ /dev/null @@ -1,153 +0,0 @@ -package mem_virtual - -import "core:mem" - -Static_Arena :: struct { - block: ^Memory_Block, - total_used: uint, - total_reserved: uint, - - minimum_block_size: uint, - temp_count: int, -} - -STATIC_ARENA_DEFAULT_COMMIT_SIZE :: 1<<20 // 1 MiB should be enough to start with - -// 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default -STATIC_ARENA_DEFAULT_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27 - -static_arena_init :: proc(arena: ^Static_Arena, reserved: uint, commit_size: uint = STATIC_ARENA_DEFAULT_COMMIT_SIZE) -> (err: Allocator_Error) { - arena.block = memory_block_alloc(commit_size, reserved, {}) or_return - arena.total_used = 0 - arena.total_reserved = arena.block.reserved - return -} - -static_arena_destroy :: proc(arena: ^Static_Arena) { - memory_block_dealloc(arena.block) - arena^ = {} -} - - -static_arena_alloc :: proc(arena: ^Static_Arena, size: int, alignment: int) -> (data: []byte, err: Allocator_Error) { - align_forward :: #force_inline proc "contextless" (ptr: uint, align: uint) -> uint { - mask := align-1 - return (ptr + mask) &~ mask - } - - if arena.block == nil { - reserve_size := max(arena.minimum_block_size, STATIC_ARENA_DEFAULT_RESERVE_SIZE) - static_arena_init(arena, reserve_size, STATIC_ARENA_DEFAULT_COMMIT_SIZE) or_return - } - - MINIMUM_ALIGN :: 2*align_of(uintptr) - - defer arena.total_used = arena.block.used - return alloc_from_memory_block(arena.block, size, max(MINIMUM_ALIGN, alignment)) -} - -static_arena_reset_to :: proc(arena: ^Static_Arena, pos: uint) -> bool { - if arena.block != nil { - prev_pos := arena.block.used - arena.block.used = clamp(pos, 0, arena.block.reserved) - - if prev_pos < pos { - mem.zero_slice(arena.block.base[arena.block.used:][:pos-prev_pos]) - } - return true - } else if pos == 0 { - return true - } - return false -} - -static_arena_free_all :: proc(arena: ^Static_Arena) { - static_arena_reset_to(arena, 0) -} - - -static_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) { - bootstrap: Static_Arena - bootstrap.minimum_block_size = reserved - - data := static_arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return - - ptr = (^T)(raw_data(data)) - - (^Static_Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap - - return -} - -static_arena_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) { - return static_arena_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved) -} -static_arena_bootstrap_new :: proc{ - static_arena_bootstrap_new_by_offset, - static_arena_bootstrap_new_by_name, -} - - -static_arena_allocator :: proc(arena: ^Static_Arena) -> mem.Allocator { - return mem.Allocator{static_arena_allocator_proc, arena} -} - -static_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, - location := #caller_location) -> (data: []byte, err: Allocator_Error) { - arena := (^Static_Arena)(allocator_data) - - switch mode { - case .Alloc: - return static_arena_alloc(arena, size, alignment) - case .Free: - err = .Mode_Not_Implemented - return - case .Free_All: - static_arena_free_all(arena) - return - case .Resize: - return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, static_arena_allocator(arena), location) - - case .Query_Features, .Query_Info: - err = .Mode_Not_Implemented - return - } - - err = .Mode_Not_Implemented - return -} - - -Static_Arena_Temp :: struct { - arena: ^Static_Arena, - used: uint, -} - - -static_arena_temp_begin :: proc(arena: ^Static_Arena) -> (temp: Static_Arena_Temp) { - temp.arena = arena - temp.used = arena.block.used if arena.block != nil else 0 - arena.temp_count += 1 - return -} - -static_arena_temp_end :: proc(temp: Static_Arena_Temp, loc := #caller_location) { - assert(temp.arena != nil, "nil arena", loc) - arena := temp.arena - - used := arena.block.used if arena.block != nil else 0 - - assert(temp.used >= used, "invalid Static_Arena_Temp", loc) - - static_arena_reset_to(arena, temp.used) - - assert(arena.temp_count > 0, "double-use of static_arena_temp_end", loc) - arena.temp_count -= 1 -} - - -static_arena_check_temp :: proc(arena: ^Static_Arena, loc := #caller_location) { - assert(arena.temp_count == 0, "Static_Arena_Temp not been ended", loc) -} \ No newline at end of file diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin index 22e96f6bd..426482fff 100644 --- a/core/mem/virtual/virtual.odin +++ b/core/mem/virtual/virtual.odin @@ -1,6 +1,7 @@ package mem_virtual import "core:mem" +import "core:intrinsics" DEFAULT_PAGE_SIZE := uint(4096) @@ -106,7 +107,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) return &pmblock.block, nil } -alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) -> (data: []byte, err: Allocator_Error) { +alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) -> (data: []byte, err: Allocator_Error) { calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint { alignment_offset := uint(0) ptr := uintptr(block.base[block.used:]) @@ -134,11 +135,14 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) return nil } - alignment_offset := calc_alignment_offset(block, uintptr(alignment)) - size := uint(min_size) + alignment_offset + size, size_ok := safe_add(min_size, alignment_offset) + if !size_ok { + err = .Out_Of_Memory + return + } - if block.used + size > block.reserved { + if to_be_used, ok := safe_add(block.used, size); !ok || to_be_used > block.reserved { err = .Out_Of_Memory return } @@ -162,3 +166,10 @@ memory_block_dealloc :: proc(block_to_free: ^Memory_Block) { } } + + +@(private) +safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) { + z, did_overflow := intrinsics.overflow_add(x, y) + return z, !did_overflow +} \ No newline at end of file diff --git a/core/mem/virtual/virtual_platform.odin b/core/mem/virtual/virtual_platform.odin index 367346f63..2f167cbeb 100644 --- a/core/mem/virtual/virtual_platform.odin +++ b/core/mem/virtual/virtual_platform.odin @@ -63,7 +63,6 @@ platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_ return .Out_Of_Memory } - commit(block, to_commit) or_return block.committed = to_commit return nil