From c909e8e4b8bf986dd7c57bd527e0c5152da3c3d6 Mon Sep 17 00:00:00 2001 From: hikari Date: Wed, 12 Oct 2022 04:35:41 +0300 Subject: [PATCH 01/17] sys/windows: add SHFileOperationW --- core/sys/windows/shell32.odin | 1 + core/sys/windows/types.odin | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/core/sys/windows/shell32.odin b/core/sys/windows/shell32.odin index a3d6c6fb8..10a7d37d3 100644 --- a/core/sys/windows/shell32.odin +++ b/core/sys/windows/shell32.odin @@ -19,4 +19,5 @@ foreign shell32 { pszPath: LPCWSTR, psa: ^SECURITY_ATTRIBUTES, ) -> c_int --- + SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int --- } diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 30cc62451..b9ff6998a 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -925,6 +925,48 @@ NM_FONTCHANGED :: NM_OUTOFMEMORY-22 NM_CUSTOMTEXT :: NM_OUTOFMEMORY-23 // uses NMCUSTOMTEXT struct NM_TVSTATEIMAGECHANGING :: NM_OUTOFMEMORY-23 // uses NMTVSTATEIMAGECHANGING struct, defined after HTREEITEM +PCZZWSTR :: ^WCHAR + +SHFILEOPSTRUCTW :: struct { + hwnd: HWND, + wFunc: UINT, + pFrom: PCZZWSTR, + pTo: PCZZWSTR, + fFlags: FILEOP_FLAGS, + fAnyOperationsAborted: BOOL, + hNameMappings: LPVOID, + lpszProgressTitle: PCWSTR, // only used if FOF_SIMPLEPROGRESS +} +LPSHFILEOPSTRUCTW :: ^SHFILEOPSTRUCTW + +// Shell File Operations +FO_MOVE :: 0x0001 +FO_COPY :: 0x0002 +FO_DELETE :: 0x0003 +FO_RENAME :: 0x0004 + +// SHFILEOPSTRUCT.fFlags and IFileOperation::SetOperationFlags() flag values +FOF_MULTIDESTFILES :: 0x0001 +FOF_CONFIRMMOUSE :: 0x0002 +FOF_SILENT :: 0x0004 // don't display progress UI (confirm prompts may be displayed still) +FOF_RENAMEONCOLLISION :: 0x0008 // automatically rename the source files to avoid the collisions +FOF_NOCONFIRMATION :: 0x0010 // don't display confirmation UI, assume "yes" for cases that can be bypassed, "no" for those that can not +FOF_WANTMAPPINGHANDLE :: 0x0020 // Fill in SHFILEOPSTRUCT.hNameMappings + // Must be freed using SHFreeNameMappings +FOF_ALLOWUNDO :: 0x0040 // enable undo including Recycle behavior for IFileOperation::Delete() +FOF_FILESONLY :: 0x0080 // only operate on the files (non folders), both files and folders are assumed without this +FOF_SIMPLEPROGRESS :: 0x0100 // means don't show names of files +FOF_NOCONFIRMMKDIR :: 0x0200 // don't dispplay confirmatino UI before making any needed directories, assume "Yes" in these cases +FOF_NOERRORUI :: 0x0400 // don't put up error UI, other UI may be displayed, progress, confirmations +FOF_NOCOPYSECURITYATTRIBS :: 0x0800 // dont copy file security attributes (ACLs) +FOF_NORECURSION :: 0x1000 // don't recurse into directories for operations that would recurse +FOF_NO_CONNECTED_ELEMENTS :: 0x2000 // don't operate on connected elements ("xxx_files" folders that go with .htm files) +FOF_WANTNUKEWARNING :: 0x4000 // during delete operation, warn if object is being permanently destroyed instead of recycling (partially overrides FOF_NOCONFIRMATION) +FOF_NORECURSEREPARSE :: 0x8000 // deprecated; the operations engine always does the right thing on FolderLink objects (symlinks, reparse points, folder shortcuts) +FOF_NO_UI :: (FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR) // don't display any UI at all + +FILEOP_FLAGS :: WORD + DEVMODEW :: struct { dmDeviceName: [32]wchar_t, dmSpecVersion: WORD, From 6642e1fc9df0e7419d067a44fb161994bff8f73c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Oct 2022 19:10:04 +0100 Subject: [PATCH 02/17] Unify `Static_Arena` and `Growing_Arena` into `Arena` --- core/mem/virtual/arena.odin | 270 ++++++++++++++++++++++++++++ core/mem/virtual/arena_util.odin | 64 +++---- core/mem/virtual/growing_arena.odin | 170 ------------------ core/mem/virtual/static_arena.odin | 153 ---------------- 4 files changed, 302 insertions(+), 355 deletions(-) create mode 100644 core/mem/virtual/arena.odin delete mode 100644 core/mem/virtual/growing_arena.odin delete mode 100644 core/mem/virtual/static_arena.odin diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin new file mode 100644 index 000000000..21c3db2ee --- /dev/null +++ b/core/mem/virtual/arena.odin @@ -0,0 +1,270 @@ +package mem_virtual + +import "core:mem" + +Arena_Kind :: enum u8 { + Growing = 0, // chained memory block + Static = 1, // fixed reservation +} + +Arena :: struct { + curr_block: ^Memory_Block, + total_used: uint, + total_reserved: uint, + + kind: Arena_Kind, + minimum_block_size: uint, + temp_count: int, +} + + +STATIC_ARENA_DEFAULT_COMMIT_SIZE :: 1<<20 // 1 MiB should be enough to start with +GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE :: STATIC_ARENA_DEFAULT_COMMIT_SIZE + +// 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 + + + +arena_init_growing :: proc(arena: ^Arena, reserved: uint = GROWING_ARENA_DEFAULT_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 +} + + +arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = STATIC_ARENA_DEFAULT_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 +} + +arena_alloc :: proc(arena: ^Arena, min_size: int, alignment: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { + align_forward_offset :: proc "contextless" (arena: ^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)), "non-power of two alignment", loc) + + switch arena.kind { + case .Growing: + 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(GROWING_ARENA_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 + } + case .Static: + if arena.curr_block == nil { + reserve_size := max(arena.minimum_block_size, STATIC_ARENA_DEFAULT_RESERVE_SIZE) + arena_init_static(arena, reserve_size, STATIC_ARENA_DEFAULT_COMMIT_SIZE) or_return + } + data, err = alloc_from_memory_block(arena.curr_block, min_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]) + } + return true + } else if pos == 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) + } + case .Static: + arena_static_reset_to(arena, 0) + } + arena.total_used = 0 + arena.total_reserved = 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_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = GROWING_ARENA_DEFAULT_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 +} + +arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = GROWING_ARENA_DEFAULT_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) +} + +arena_growing_bootstrap_new :: proc{ + arena_growing_bootstrap_new_by_offset, + arena_growing_bootstrap_new_by_name, +} + +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 +} + +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) +} +arena_static_bootstrap_new :: proc{ + arena_static_bootstrap_new_by_offset, + arena_static_bootstrap_new_by_name, +} + + +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) + + switch mode { + case .Alloc: + return arena_alloc(arena, size, alignment) + case .Free: + err = .Mode_Not_Implemented + return + case .Free_All: + arena_free_all(arena) + return + case .Resize: + return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena), location) + + case .Query_Features, .Query_Info: + err = .Mode_Not_Implemented + return + } + + err = .Mode_Not_Implemented + return +} + +Arena_Temp :: struct { + arena: ^Arena, + block: ^Memory_Block, + used: uint, +} + +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 index 0e152db7a..f721c4ffa 100644 --- a/core/mem/virtual/arena_util.odin +++ b/core/mem/virtual/arena_util.odin @@ -1,41 +1,41 @@ package mem_virtual -arena_init :: proc{ - static_arena_init, - growing_arena_init, -} +// arena_init :: proc{ +// static_arena_init, +// growing_arena_init, +// } -arena_temp_begin :: proc{ - static_arena_temp_begin, - growing_arena_temp_begin, -} +// 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_temp_end :: proc{ +// static_arena_temp_end, +// growing_arena_temp_end, +// } -arena_check_temp :: proc{ - static_arena_check_temp, - growing_arena_check_temp, -} +// arena_check_temp :: proc{ +// static_arena_check_temp, +// growing_arena_check_temp, +// } -arena_allocator :: proc{ - static_arena_allocator, - growing_arena_allocator, -} +// arena_allocator :: proc{ +// static_arena_allocator, +// growing_arena_allocator, +// } -arena_alloc :: proc{ - static_arena_alloc, - growing_arena_alloc, -} +// arena_alloc :: proc{ +// static_arena_alloc, +// growing_arena_alloc, +// } -arena_free_all :: proc{ - static_arena_free_all, - growing_arena_free_all, -} +// 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 +// 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 From b84108c4b55e94c495dc7d9d57404455d023ca7f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Oct 2022 20:28:51 +0100 Subject: [PATCH 03/17] Inline align forward offset code --- core/mem/virtual/arena.odin | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 21c3db2ee..ba2708fc3 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -44,23 +44,18 @@ arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = STA } arena_alloc :: proc(arena: ^Arena, min_size: int, alignment: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { - align_forward_offset :: proc "contextless" (arena: ^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)), "non-power of two alignment", loc) switch arena.kind { case .Growing: - size := uint(0) + size := uint(min_size) if arena.curr_block != nil { - size = uint(min_size) + align_forward_offset(arena, alignment) + // align forward offset + ptr := uintptr(arena.curr_block.base[arena.curr_block.used:]) + mask := uintptr(alignment-1) + if ptr & mask != 0 { + size += uint(alignment) - uint(ptr & mask) + } } if arena.curr_block == nil || arena.curr_block.used + size > arena.curr_block.reserved { From 835b8ffa22d7dce1a4b3cd1677a50095200a3883 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Oct 2022 20:30:48 +0100 Subject: [PATCH 04/17] Update `total_used` for `arena_static_reset_to` --- core/mem/virtual/arena.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index ba2708fc3..d2ffa73f2 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -96,8 +96,10 @@ arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) 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 From 5c62211f00ca1f11a92e7a97b3727b9e29fb0ebd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Oct 2022 20:44:36 +0100 Subject: [PATCH 05/17] Inline resize logic for `virtual.Arena` --- core/mem/alloc.odin | 15 +++++++------ core/mem/virtual/arena.odin | 45 +++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 16 deletions(-) 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 index d2ffa73f2..1dd8d249c 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -46,6 +46,10 @@ arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = STA arena_alloc :: proc(arena: ^Arena, min_size: int, alignment: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { assert(mem.is_power_of_two(uintptr(alignment)), "non-power of two alignment", loc) + if min_size == 0 { + return nil, nil + } + switch arena.kind { case .Growing: size := uint(min_size) @@ -186,9 +190,9 @@ arena_allocator :: proc(arena: ^Arena) -> mem.Allocator { } 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) { + size, alignment: int, + old_memory: rawptr, old_size: int, + location := #caller_location) -> (data: []byte, err: Allocator_Error) { arena := (^Arena)(allocator_data) switch mode { @@ -196,19 +200,42 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, return arena_alloc(arena, size, alignment) case .Free: err = .Mode_Not_Implemented - return case .Free_All: arena_free_all(arena) - return case .Resize: - return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena), location) + old_data := ([^]byte)(old_memory) - case .Query_Features, .Query_Info: + 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 } - err = .Mode_Not_Implemented return } From 5a8fbc230da9d16a1f8f4345bc7c803fe8f77bab Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Oct 2022 21:16:34 +0100 Subject: [PATCH 06/17] Sanity corrections to virtual calls --- core/mem/virtual/arena.odin | 57 ++++++++++++-------------- core/mem/virtual/virtual.odin | 2 +- core/mem/virtual/virtual_platform.odin | 1 - 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 1dd8d249c..e95dc227c 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -18,7 +18,8 @@ Arena :: struct { } -STATIC_ARENA_DEFAULT_COMMIT_SIZE :: 1<<20 // 1 MiB should be enough to start with +// 1 MiB should be enough to start with +STATIC_ARENA_DEFAULT_COMMIT_SIZE :: 1<<20 GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE :: STATIC_ARENA_DEFAULT_COMMIT_SIZE // 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default @@ -43,27 +44,18 @@ arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = STA return } -arena_alloc :: proc(arena: ^Arena, min_size: int, alignment: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { +arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { assert(mem.is_power_of_two(uintptr(alignment)), "non-power of two alignment", loc) - if min_size == 0 { + size := size + if size == 0 { return nil, nil } switch arena.kind { case .Growing: - size := uint(min_size) - if arena.curr_block != nil { - // align forward offset - ptr := uintptr(arena.curr_block.base[arena.curr_block.used:]) - mask := uintptr(alignment-1) - if ptr & mask != 0 { - size += uint(alignment) - uint(ptr & mask) - } - } - if arena.curr_block == nil || arena.curr_block.used + size > arena.curr_block.reserved { - size = uint(mem.align_forward_int(min_size, alignment)) + size = mem.align_forward_uint(size, alignment) arena.minimum_block_size = max(GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE, arena.minimum_block_size) block_size := max(size, arena.minimum_block_size) @@ -74,17 +66,15 @@ arena_alloc :: proc(arena: ^Arena, min_size: int, alignment: int, loc := #caller 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 - } + 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 { reserve_size := max(arena.minimum_block_size, STATIC_ARENA_DEFAULT_RESERVE_SIZE) arena_init_static(arena, reserve_size, STATIC_ARENA_DEFAULT_COMMIT_SIZE) or_return } - data, err = alloc_from_memory_block(arena.curr_block, min_size, alignment) + data, err = alloc_from_memory_block(arena.curr_block, size, alignment) arena.total_used = arena.curr_block.used } return @@ -123,11 +113,11 @@ arena_free_all :: proc(arena: ^Arena) { 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.total_reserved = 0 } arena_destroy :: proc(arena: ^Arena) { @@ -139,6 +129,16 @@ arena_destroy :: proc(arena: ^Arena) { 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, +} + arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { bootstrap: Arena bootstrap.kind = .Growing @@ -157,11 +157,6 @@ arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, min return arena_growing_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size) } -arena_growing_bootstrap_new :: proc{ - arena_growing_bootstrap_new_by_offset, - arena_growing_bootstrap_new_by_name, -} - 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 @@ -179,10 +174,6 @@ arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintpt 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) } -arena_static_bootstrap_new :: proc{ - arena_static_bootstrap_new_by_offset, - arena_static_bootstrap_new_by_name, -} arena_allocator :: proc(arena: ^Arena) -> mem.Allocator { @@ -195,6 +186,9 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, 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) @@ -239,6 +233,9 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, return } + + + Arena_Temp :: struct { arena: ^Arena, block: ^Memory_Block, diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin index 22e96f6bd..e023b2324 100644 --- a/core/mem/virtual/virtual.odin +++ b/core/mem/virtual/virtual.odin @@ -106,7 +106,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:]) 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 From 765cd66b30f2da13ffc911b56e258a92f0d8ebdb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Oct 2022 21:20:31 +0100 Subject: [PATCH 07/17] Clean up `minimum_block_size` default implicit initialization --- core/mem/virtual/arena.odin | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index e95dc227c..33d25e3a5 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -56,7 +56,9 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l case .Growing: if arena.curr_block == nil || arena.curr_block.used + size > arena.curr_block.reserved { size = mem.align_forward_uint(size, alignment) - arena.minimum_block_size = max(GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE, arena.minimum_block_size) + if arena.minimum_block_size == 0 { + arena.minimum_block_size = GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE + } block_size := max(size, arena.minimum_block_size) @@ -71,8 +73,10 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l arena.total_used += arena.curr_block.used - prev_used case .Static: if arena.curr_block == nil { - reserve_size := max(arena.minimum_block_size, STATIC_ARENA_DEFAULT_RESERVE_SIZE) - arena_init_static(arena, reserve_size, STATIC_ARENA_DEFAULT_COMMIT_SIZE) or_return + if arena.minimum_block_size == 0 { + arena.minimum_block_size = STATIC_ARENA_DEFAULT_RESERVE_SIZE + } + arena_init_static(arena=arena, reserved=arena.minimum_block_size, commit_size=STATIC_ARENA_DEFAULT_COMMIT_SIZE) or_return } data, err = alloc_from_memory_block(arena.curr_block, size, alignment) arena.total_used = arena.curr_block.used From 5ed06f7eb8b2e84844d7384e5e91ce59ab94340e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Oct 2022 21:23:45 +0100 Subject: [PATCH 08/17] Rename constants; minor rearrange of `Arena` layout --- core/mem/virtual/arena.odin | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 33d25e3a5..af26b950e 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -2,32 +2,31 @@ package mem_virtual import "core:mem" -Arena_Kind :: enum u8 { - Growing = 0, // chained memory block - Static = 1, // fixed reservation +Arena_Kind :: enum uint { + Growing = 0, // chained memory blocks (singly linked list) + Static = 1, // fixed reservation sized } Arena :: struct { - curr_block: ^Memory_Block, - total_used: uint, - total_reserved: uint, - kind: Arena_Kind, + curr_block: ^Memory_Block, + total_used: uint, + total_reserved: uint, minimum_block_size: uint, - temp_count: int, + temp_count: uint, } // 1 MiB should be enough to start with -STATIC_ARENA_DEFAULT_COMMIT_SIZE :: 1<<20 -GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE :: STATIC_ARENA_DEFAULT_COMMIT_SIZE +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 -STATIC_ARENA_DEFAULT_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27 +DEFAULT_ARENA_STATIC_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27 -arena_init_growing :: proc(arena: ^Arena, reserved: uint = GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) { +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 @@ -36,7 +35,7 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = GROWING_ARENA_DEFAULT } -arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = STATIC_ARENA_DEFAULT_COMMIT_SIZE) -> (err: Allocator_Error) { +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 @@ -57,7 +56,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l if arena.curr_block == nil || arena.curr_block.used + size > arena.curr_block.reserved { size = mem.align_forward_uint(size, alignment) if arena.minimum_block_size == 0 { - arena.minimum_block_size = GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE + arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE } block_size := max(size, arena.minimum_block_size) @@ -74,9 +73,9 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l case .Static: if arena.curr_block == nil { if arena.minimum_block_size == 0 { - arena.minimum_block_size = STATIC_ARENA_DEFAULT_RESERVE_SIZE + arena.minimum_block_size = DEFAULT_ARENA_STATIC_RESERVE_SIZE } - arena_init_static(arena=arena, reserved=arena.minimum_block_size, commit_size=STATIC_ARENA_DEFAULT_COMMIT_SIZE) or_return + 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 @@ -143,7 +142,7 @@ arena_static_bootstrap_new :: proc{ arena_static_bootstrap_new_by_name, } -arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { +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 @@ -157,7 +156,7 @@ arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintp return } -arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = GROWING_ARENA_DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { +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) } From cf4afc2e7b2e6a5219cbc25ca9d2039261d1e939 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Oct 2022 21:26:50 +0100 Subject: [PATCH 09/17] Inline `assert` condition --- core/mem/virtual/arena.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index af26b950e..ab66f3685 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -44,7 +44,7 @@ arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = DEF } arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { - assert(mem.is_power_of_two(uintptr(alignment)), "non-power of two alignment", loc) + assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc) size := size if size == 0 { From 2c14f0a109a25730fbe568a6710a1b943ff08132 Mon Sep 17 00:00:00 2001 From: hikari Date: Thu, 13 Oct 2022 11:19:05 +0300 Subject: [PATCH 10/17] sys/windows: add ITaskbarList interfaces --- core/sys/windows/types.odin | 82 +++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index b9ff6998a..af28a9060 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -3232,10 +3232,14 @@ LWSTDAPI :: HRESULT CLSID_FileOpenDialog := &GUID{0xDC1C5A9C, 0xE88A, 0x4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}} CLSID_FileSaveDialog := &GUID{0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}} +CLSID_TaskbarList := &GUID{0x56FDF344, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}} IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}} IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}} +IID_ITaskbarList := &GUID{0x56FDF342, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}} +IID_ITaskbarList2 := &GUID{0x602D4995, 0xB13A, 0x429b, {0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17}} +IID_ITaskbarList3 := &GUID{0xea1afb91, 0x9e28, 0x4b86, {0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf}} IModalWindow :: struct #raw_union { #subtype IUnknown: IUnknown, @@ -3540,6 +3544,84 @@ IFileSaveDialogVtbl :: struct { ApplyProperties: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT, } +ITaskbarList :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^ITaskbarListVtbl, +} +ITaskbarListVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + HrInit: proc "stdcall" (this: ^ITaskbarList) -> HRESULT, + AddTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT, + DeleteTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT, + ActivateTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT, + SetActiveAlt: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT, +} + +ITaskbarList2 :: struct #raw_union { + #subtype ITaskbarList: ITaskbarList, + using Vtbl: ^ITaskbarList2Vtbl, +} +ITaskbarList2Vtbl :: struct { + using ITaskbarListVtbl: ITaskbarListVtbl, + MarkFullscreenWindow: proc "stdcall" (this: ^ITaskbarList2, hwnd: HWND, fFullscreen: BOOL) -> HRESULT, +} + +TBPFLAG :: enum c_int { + NOPROGRESS = 0, + INDETERMINATE = 0x1, + NORMAL = 0x2, + ERROR = 0x4, + PAUSED = 0x8, +} + +THUMBBUTTONFLAGS :: enum c_int { + ENABLED = 0, + DISABLED = 0x1, + DISMISSONCLICK = 0x2, + NOBACKGROUND = 0x4, + HIDDEN = 0x8, + NONINTERACTIVE = 0x10, +} + +THUMBBUTTONMASK :: enum c_int { + BITMAP = 0x1, + ICON = 0x2, + TOOLTIP = 0x4, + FLAGS = 0x8, +} + +THUMBBUTTON :: struct { + dwMask: THUMBBUTTONMASK, + iId: UINT, + iBitmap: UINT, + hIcon: HICON, + szTip: [260]WCHAR, + dwFlags: THUMBBUTTONFLAGS, +} +LPTHUMBBUTTON :: ^THUMBBUTTON + +HIMAGELIST :: ^IUnknown + +ITaskbarList3 :: struct #raw_union { + #subtype ITaskbarList2: ITaskbarList2, + using Vtbl: ^ITaskbarList3Vtbl, +} +ITaskbarList3Vtbl :: struct { + using ITaskbarList2Vtbl: ITaskbarList2Vtbl, + SetProgressValue: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, ullCompleted: ULONGLONG, ullTotal: ULONGLONG) -> HRESULT, + SetProgressState: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, tbpFlags: TBPFLAG) -> HRESULT, + RegisterTab: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndMDI: HWND) -> HRESULT, + UnregisterTab: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND) -> HRESULT, + SetTabOrder: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndInsertBefore: HWND) -> HRESULT, + SetTabActive: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndMDI: HWND, dwReserved: DWORD) -> HRESULT, + ThumbBarAddButtons: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, cButtons: UINT, pButton: LPTHUMBBUTTON) -> HRESULT, + ThumbBarUpdateButtons: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, cButtons: UINT, pButton: LPTHUMBBUTTON) -> HRESULT, + ThumbBarSetImageList: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, himl: HIMAGELIST) -> HRESULT, + SetOverlayIcon: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, hIcon: HICON, pszDescription: LPCWSTR) -> HRESULT, + SetThumbnailTooltip: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, pszTip: LPCWSTR) -> HRESULT, + SetThumbnailClip: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, prcClip: ^RECT) -> HRESULT, +} + MEMORYSTATUSEX :: struct { dwLength: DWORD, dwMemoryLoad: DWORD, From b725e01cddc32045b35fc44ed0b1e1df1bb7fbfe Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 13 Oct 2022 11:10:16 +0100 Subject: [PATCH 11/17] Add @(require_results) to many procedures --- core/mem/virtual/arena.odin | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index ab66f3685..3cc4cdbd6 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -26,6 +26,7 @@ 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 @@ -35,6 +36,7 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING } +@(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 @@ -43,6 +45,7 @@ arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = DEF 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) @@ -142,6 +145,7 @@ arena_static_bootstrap_new :: proc{ 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 @@ -156,10 +160,12 @@ arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintp 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 @@ -174,11 +180,13 @@ arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintpt 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} } @@ -245,6 +253,7 @@ Arena_Temp :: struct { 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 From d48828dd80ef8419e8b1dab4178340e654322719 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 13 Oct 2022 12:45:17 +0100 Subject: [PATCH 12/17] Add overflow check when using a growing arena --- core/mem/virtual/arena.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 3cc4cdbd6..57dbc2168 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -1,6 +1,7 @@ package mem_virtual import "core:mem" +import "core:intrinsics" Arena_Kind :: enum uint { Growing = 0, // chained memory blocks (singly linked list) @@ -56,7 +57,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l switch arena.kind { case .Growing: - if arena.curr_block == nil || arena.curr_block.used + size > arena.curr_block.reserved { + if arena.curr_block == nil || (intrinsics.overflow_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 From 7662808bc92271bbd5c9d6fad27301055f7e00ce Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 13 Oct 2022 12:53:33 +0100 Subject: [PATCH 13/17] Add `overflow_add` checks to `alloc_from_memory_block` --- core/mem/virtual/virtual.odin | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin index e023b2324..b209d06e4 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) @@ -134,11 +135,14 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) return nil } - alignment_offset := calc_alignment_offset(block, uintptr(alignment)) - size := uint(min_size) + alignment_offset + size, size_ok := intrinsics.overflow_add(min_size, alignment_offset) + if !size_ok { + err = .Out_Of_Memory + return + } - if block.used + size > block.reserved { + if to_be_used, ok := intrinsics.overflow_add(block.used, size); !ok || to_be_used > block.reserved { err = .Out_Of_Memory return } From 06d1df4cae548e5baee226c570920e96eaca3ca1 Mon Sep 17 00:00:00 2001 From: terids Date: Fri, 14 Oct 2022 02:03:57 +0100 Subject: [PATCH 14/17] Fix GetInstanceProcAddr crash It was trying to initialise itself with itself when calling load_proc_addresses(Instance) Discord bug channel reference https://discord.com/channels/568138951836172421/585072813954564100/1030265964572450867 --- vendor/vulkan/_gen/create_vulkan_odin_wrapper.py | 14 +++++++------- vendor/vulkan/procedures.odin | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index 9a32f5796..1dbac58d8 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -84,7 +84,7 @@ def convert_type(t, prev_name, curr_name): else: ttype = t[:len(t)-1] elem = convert_type(ttype, prev_name, curr_name) - + if curr_name.endswith("s") or curr_name.endswith("Table"): if prev_name.endswith("Count") or prev_name.endswith("Counts"): pointer = "[^]" @@ -95,10 +95,10 @@ def convert_type(t, prev_name, curr_name): pointer = "[^]" elif curr_name.startswith("p"): pointer = "[^]" - + if curr_name and elem.endswith("Flags"): pointer = "[^]" - + return "{}{}".format(pointer, elem) elif t[0].isupper(): return t @@ -276,7 +276,7 @@ def parse_enums(f): f.write("// Enums\n") data = re.findall(r"typedef enum Vk(\w+) {(.+?)} \w+;", src, re.S) - + data.sort(key=lambda x: x[0]) generated_flags = set() @@ -458,14 +458,14 @@ def parse_procedures(f): for rt, name, fields in data: proc_name = no_vk(name) - + pf = [] prev_name = "" for type_, fname in re.findall(r"(?:\s*|)(.+?)\s*(\w+)(?:,|$)", fields): curr_name = fix_arg(fname) pf.append((do_type(type_, prev_name, curr_name), curr_name)) prev_name = curr_name - + data_fields = ', '.join(["{}: {}".format(n, t) for t, n in pf if t != ""]) ts = "proc \"c\" ({})".format(data_fields) @@ -510,7 +510,7 @@ def group_functions(f): if table_name in ('Device', 'Queue', 'CommandBuffer') and name != 'GetDeviceProcAddr': group_map["Device"].append(nn) - elif table_name in ('Instance', 'PhysicalDevice') or name == 'GetDeviceProcAddr': + elif table_name in ('Instance', 'PhysicalDevice') and name != 'ProcGetInstanceProcAddr' or name == 'GetDeviceProcAddr': group_map["Instance"].append(nn) elif table_name in ('rawptr', '', 'DebugReportFlagsEXT') or name == 'GetInstanceProcAddr': # Skip the allocation function and the dll entry point diff --git a/vendor/vulkan/procedures.odin b/vendor/vulkan/procedures.odin index 227f02a87..02cfa9dbf 100644 --- a/vendor/vulkan/procedures.odin +++ b/vendor/vulkan/procedures.odin @@ -533,6 +533,7 @@ DeviceMemoryReportCallbackEXT: ProcDeviceMemoryReportCallbackEXT EnumerateInstanceExtensionProperties: ProcEnumerateInstanceExtensionProperties EnumerateInstanceLayerProperties: ProcEnumerateInstanceLayerProperties EnumerateInstanceVersion: ProcEnumerateInstanceVersion +GetInstanceProcAddr: ProcGetInstanceProcAddr // Instance Procedures AcquireDrmDisplayEXT: ProcAcquireDrmDisplayEXT @@ -564,7 +565,6 @@ GetDisplayPlaneCapabilities2KHR: ProcGetDisplayP GetDisplayPlaneCapabilitiesKHR: ProcGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneSupportedDisplaysKHR: ProcGetDisplayPlaneSupportedDisplaysKHR GetDrmDisplayEXT: ProcGetDrmDisplayEXT -GetInstanceProcAddr: ProcGetInstanceProcAddr GetPhysicalDeviceCalibrateableTimeDomainsEXT: ProcGetPhysicalDeviceCalibrateableTimeDomainsEXT GetPhysicalDeviceCooperativeMatrixPropertiesNV: ProcGetPhysicalDeviceCooperativeMatrixPropertiesNV GetPhysicalDeviceDisplayPlaneProperties2KHR: ProcGetPhysicalDeviceDisplayPlaneProperties2KHR @@ -1045,6 +1045,7 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&EnumerateInstanceExtensionProperties, "vkEnumerateInstanceExtensionProperties") set_proc_address(&EnumerateInstanceLayerProperties, "vkEnumerateInstanceLayerProperties") set_proc_address(&EnumerateInstanceVersion, "vkEnumerateInstanceVersion") + set_proc_address(&GetInstanceProcAddr, "vkGetInstanceProcAddr") // Instance Procedures set_proc_address(&AcquireDrmDisplayEXT, "vkAcquireDrmDisplayEXT") @@ -1076,7 +1077,6 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&GetDisplayPlaneCapabilitiesKHR, "vkGetDisplayPlaneCapabilitiesKHR") set_proc_address(&GetDisplayPlaneSupportedDisplaysKHR, "vkGetDisplayPlaneSupportedDisplaysKHR") set_proc_address(&GetDrmDisplayEXT, "vkGetDrmDisplayEXT") - set_proc_address(&GetInstanceProcAddr, "vkGetInstanceProcAddr") set_proc_address(&GetPhysicalDeviceCalibrateableTimeDomainsEXT, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT") set_proc_address(&GetPhysicalDeviceCooperativeMatrixPropertiesNV, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV") set_proc_address(&GetPhysicalDeviceDisplayPlaneProperties2KHR, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR") @@ -2839,7 +2839,6 @@ load_proc_addresses_instance :: proc(instance: Instance) { GetDisplayPlaneCapabilitiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR") GetDisplayPlaneSupportedDisplaysKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR") GetDrmDisplayEXT = auto_cast GetInstanceProcAddr(instance, "vkGetDrmDisplayEXT") - GetInstanceProcAddr = auto_cast GetInstanceProcAddr(instance, "vkGetInstanceProcAddr") GetPhysicalDeviceCalibrateableTimeDomainsEXT = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT") GetPhysicalDeviceCooperativeMatrixPropertiesNV = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV") GetPhysicalDeviceDisplayPlaneProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR") @@ -3322,6 +3321,7 @@ load_proc_addresses_global :: proc(vk_get_instance_proc_addr: rawptr) { EnumerateInstanceExtensionProperties = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceExtensionProperties") EnumerateInstanceLayerProperties = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceLayerProperties") EnumerateInstanceVersion = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceVersion") + GetInstanceProcAddr = auto_cast GetInstanceProcAddr(nil, "vkGetInstanceProcAddr") } load_proc_addresses :: proc{ From 73c1f08776688f18940abcbff5d5b9f0f594049d Mon Sep 17 00:00:00 2001 From: Lucas Perlind Date: Fri, 14 Oct 2022 18:22:59 +1100 Subject: [PATCH 15/17] Improve error messages with 'using _' --- src/check_decl.cpp | 5 +++++ src/check_stmt.cpp | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 9d043e60a..bb56749af 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1488,6 +1488,11 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty if (!(e->flags & EntityFlag_Using)) { continue; } + if (is_blank_ident(e->token)) { + error(e->token, "'using' a procedure parameter requires a non blank identifier"); + break; + } + bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type); String name = e->token.string; Type *t = base_type(type_deref(e->type)); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 630182273..9cacb4a35 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -584,7 +584,11 @@ void check_label(CheckerContext *ctx, Ast *label, Ast *parent) { // Returns 'true' for 'continue', 'false' for 'return' bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, bool is_selector, Entity *e) { if (e == nullptr) { - error(us->token, "'using' applied to an unknown entity"); + if (is_blank_ident(expr)) { + error(us->token, "'using' in a statement is not allowed with the blank identifier '_'"); + } else { + error(us->token, "'using' applied to an unknown entity"); + } return true; } From ff51c5ee5628774574f63e72f5efe6c49aaae54e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Oct 2022 12:52:07 +0100 Subject: [PATCH 16/17] Wrap `intrinsics.overflow_add` to `safe_add` --- core/mem/virtual/arena.odin | 6 +---- core/mem/virtual/arena_util.odin | 41 -------------------------------- core/mem/virtual/virtual.odin | 11 +++++++-- 3 files changed, 10 insertions(+), 48 deletions(-) delete mode 100644 core/mem/virtual/arena_util.odin diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 57dbc2168..45426eddc 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -1,7 +1,6 @@ package mem_virtual import "core:mem" -import "core:intrinsics" Arena_Kind :: enum uint { Growing = 0, // chained memory blocks (singly linked list) @@ -57,7 +56,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l switch arena.kind { case .Growing: - if arena.curr_block == nil || (intrinsics.overflow_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved { + 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 @@ -299,6 +298,3 @@ arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) { 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 f721c4ffa..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/virtual.odin b/core/mem/virtual/virtual.odin index b209d06e4..426482fff 100644 --- a/core/mem/virtual/virtual.odin +++ b/core/mem/virtual/virtual.odin @@ -136,13 +136,13 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) } alignment_offset := calc_alignment_offset(block, uintptr(alignment)) - size, size_ok := intrinsics.overflow_add(min_size, alignment_offset) + size, size_ok := safe_add(min_size, alignment_offset) if !size_ok { err = .Out_Of_Memory return } - if to_be_used, ok := intrinsics.overflow_add(block.used, size); !ok || to_be_used > block.reserved { + if to_be_used, ok := safe_add(block.used, size); !ok || to_be_used > block.reserved { err = .Out_Of_Memory return } @@ -166,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 From 075040ae057e48bb9df4cb03bc0ea39e98a804ad Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Oct 2022 00:06:21 +0100 Subject: [PATCH 17/17] Update sort_private.odin --- core/slice/sort_private.odin | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/slice/sort_private.odin b/core/slice/sort_private.odin index 86a6f5928..32eb7d417 100644 --- a/core/slice/sort_private.odin +++ b/core/slice/sort_private.odin @@ -177,7 +177,6 @@ _quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND } -// merge sort _stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check { less :: #force_inline proc(a, b: E, call: P) -> bool { when KIND == .Ordered { @@ -190,7 +189,9 @@ _stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (O #panic("unhandled Sort_Kind") } } - + + // insertion sort + // TODO(bill): use a different algorithm as insertion sort is O(n^2) n := len(data) for i in 1.. 0 && less(data[j], data[j-1], call); j -= 1 {