From c3b3194a00150ee0f5a9cd7b86d2b93ff72566a1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 19 Apr 2021 22:44:20 +0100 Subject: [PATCH] Update builtin procedures to support the new allocator features (without breaking other code) --- core/mem/alloc.odin | 7 +-- core/mem/allocators.odin | 4 +- core/odin/ast/ast.odin | 1 + core/odin/parser/parser.odin | 10 ++--- core/runtime/core.odin | 7 +-- core/runtime/core_builtin.odin | 68 +++++++++++++++--------------- core/runtime/core_builtin_soa.odin | 12 +++--- core/runtime/internal.odin | 9 ++-- 8 files changed, 61 insertions(+), 57 deletions(-) diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index 4425fd7d9..0df68255f 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -31,9 +31,10 @@ Allocator_Query_Info :: struct { Allocator_Error :: runtime.Allocator_Error; /* Allocator_Error :: enum byte { - None = 0, - Out_Of_Memory = 1, - Invalid_Pointer = 2, + None = 0, + Out_Of_Memory = 1, + Invalid_Pointer = 2, + Invalid_Argument = 3, } */ Allocator_Proc :: runtime.Allocator_Proc; diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 24eff1f10..282fff48c 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -313,7 +313,7 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, s := cast(^Stack)allocator_data; if s.data == nil { - return nil, .Out_Of_Memory; + return nil, .Invalid_Argument; } raw_alloc :: proc(s: ^Stack, size, alignment: int) -> ([]byte, Allocator_Error) { @@ -468,7 +468,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, s := cast(^Small_Stack)allocator_data; if s.data == nil { - return nil, .Out_Of_Memory; + return nil, .Invalid_Argument; } align := clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2); diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index e7411ebcd..0d015f9bb 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -6,6 +6,7 @@ Proc_Tag :: enum { Bounds_Check, No_Bounds_Check, Optional_Ok, + Optional_Second, } Proc_Tags :: distinct bit_set[Proc_Tag; u32]; diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 2b657f76f..160eb3a5c 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1910,12 +1910,10 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) { ident := expect_token(p, .Ident); switch ident.text { - case "bounds_check": - tags |= {.Bounds_Check}; - case "no_bounds_check": - tags |= {.No_Bounds_Check}; - case "optional_ok": - tags |= {.Optional_Ok}; + case "bounds_check": tags |= {.Bounds_Check}; + case "no_bounds_check": tags |= {.No_Bounds_Check}; + case "optional_ok": tags |= {.Optional_Ok}; + case "optional_second": tags |= {.Optional_Second}; case: } } diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 05f7a1e57..ac5e90460 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -271,9 +271,10 @@ Allocator_Query_Info :: struct { } Allocator_Error :: enum byte { - None = 0, - Out_Of_Memory = 1, - Invalid_Pointer = 2, + None = 0, + Out_Of_Memory = 1, + Invalid_Pointer = 2, + Invalid_Argument = 3, } Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode, diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 7446b496b..6656c16a0 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -127,26 +127,30 @@ free_all :: proc{mem_free_all}; @builtin -delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) { - mem_free(raw_data(str), allocator, loc); +delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { + return mem_free(raw_data(str), allocator, loc); } @builtin -delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) { - mem_free((^byte)(str), allocator, loc); +delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { + return mem_free((^byte)(str), allocator, loc); } @builtin -delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) { - mem_free(raw_data(array), array.allocator, loc); +delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error { + return mem_free(raw_data(array), array.allocator, loc); } @builtin -delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) { - mem_free(raw_data(array), allocator, loc); +delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { + return mem_free(raw_data(array), allocator, loc); } @builtin -delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) { +delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error { raw := transmute(Raw_Map)m; - delete_slice(raw.hashes, raw.entries.allocator, loc); - mem_free(raw.entries.data, raw.entries.allocator, loc); + err := delete_slice(raw.hashes, raw.entries.allocator, loc); + err1 := mem_free(raw.entries.data, raw.entries.allocator, loc); + if err == nil { + err = err1; + } + return err; } @@ -163,59 +167,57 @@ delete :: proc{ // The new built-in procedure allocates memory. The first argument is a type, not a value, and the value // return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator @builtin -new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> ^T { - ptr := (^T)(mem_alloc(size_of(T), align_of(T), allocator, loc)); - if ptr != nil { ptr^ = T{}; } - return ptr; +new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_second { + ptr, err := mem_alloc(size_of(T), align_of(T), allocator, loc); + return (^T)(ptr), err; } @builtin -new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> ^T { - ptr := (^T)(mem_alloc(size_of(T), align_of(T), allocator, loc)); - if ptr != nil { ptr^ = data; } - return ptr; +new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_second { + ptr, err := mem_alloc(size_of(T), align_of(T), allocator, loc); + res := (^T)(ptr); + if ptr != nil && err != .Out_Of_Memory { + res^ = data; + } + return res, err; } DEFAULT_RESERVE_CAPACITY :: 16; -make_aligned :: proc($T: typeid/[]$E, auto_cast len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> T { +make_aligned :: proc($T: typeid/[]$E, auto_cast len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { make_slice_error_loc(loc, len); data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc); - switch { - case err != nil: - return nil; - case data == nil && size_of(E) != 0: - return nil; + if data == nil && size_of(E) != 0 { + return nil, err; } s := Raw_Slice{raw_data(data), len}; - return transmute(T)s; + return transmute(T)s, err; } @builtin -make_slice :: proc($T: typeid/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T { +make_slice :: proc($T: typeid/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { return make_aligned(T, len, align_of(E), allocator, loc); } @builtin -make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> T { +make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc); } @builtin -make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T { +make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { return make_dynamic_array_len_cap(T, len, len, allocator, loc); } @builtin -make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, auto_cast len: int, auto_cast cap: int, allocator := context.allocator, loc := #caller_location) -> T { +make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, auto_cast len: int, auto_cast cap: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { make_dynamic_array_error_loc(loc, len, cap); - data := mem_alloc(size_of(E)*cap, align_of(E), allocator, loc); + data, err := mem_alloc(size_of(E)*cap, align_of(E), allocator, loc); s := Raw_Dynamic_Array{data, len, cap, allocator}; if data == nil && size_of(E) != 0 { s.len, s.cap = 0, 0; } - // mem_zero(data, size_of(E)*cap); - return transmute(T)s; + return transmute(T)s, err; } @builtin diff --git a/core/runtime/core_builtin_soa.odin b/core/runtime/core_builtin_soa.odin index d7de057d2..e00855c00 100644 --- a/core/runtime/core_builtin_soa.odin +++ b/core/runtime/core_builtin_soa.odin @@ -74,7 +74,7 @@ raw_soa_footer :: proc{ @builtin -make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { +make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second { if length <= 0 { return; } @@ -106,13 +106,15 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc } assert(allocator.procedure != nil); - new_data := allocator.procedure( + new_bytes: []byte; + new_bytes, err = allocator.procedure( allocator.data, .Alloc, total_size, max_align, - nil, 0, 0, loc, + nil, 0, loc, ); - if new_data == nil { + if new_bytes == nil || err != nil { return; } + new_data := raw_data(new_bytes); data := uintptr(&array); offset := 0; @@ -131,7 +133,7 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc } @builtin -make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { +make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second { return make_soa_aligned(T, length, align_of(E), allocator, loc); } diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 51f478a67..3c05fb6a7 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -169,16 +169,15 @@ mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNM return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc); } -mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { +mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) { if size == 0 { - return nil; + return nil, nil; } if allocator.procedure == nil { - return nil; + return nil, nil; } data, err := allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc); - _ = err; - return raw_data(data); + return raw_data(data), err; } mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {