diff --git a/core/compress/common.odin b/core/compress/common.odin index b42cbefff..6bcc46bf2 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -212,6 +212,8 @@ read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int @(optimization_mode="speed") read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int) -> (res: []u8, err: io.Error) { + // TODO: REMOVE ALL USE OF context.temp_allocator here + // the is literally no need for it b := make([]u8, size, context.temp_allocator) _, e := z.input->impl_read(b[:]) if e == .None { diff --git a/core/dynlib/lib_windows.odin b/core/dynlib/lib_windows.odin index d48e43ca2..67880df4b 100644 --- a/core/dynlib/lib_windows.odin +++ b/core/dynlib/lib_windows.odin @@ -4,10 +4,12 @@ package dynlib import win32 "core:sys/windows" import "core:strings" +import "core:runtime" _load_library :: proc(path: string, global_symbols := false) -> (Library, bool) { // NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wide_path := win32.utf8_to_wstring(path, context.temp_allocator) handle := cast(Library)win32.LoadLibraryW(wide_path) return handle, handle != nil @@ -19,6 +21,7 @@ _unload_library :: proc(library: Library) -> bool { } _symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() c_str := strings.clone_to_cstring(symbol, context.temp_allocator) ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str) found = ptr != nil diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index 11cae6160..1e8ec0e0d 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -346,6 +346,8 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm fields := reflect.struct_fields_zipped(ti.id) + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) + field_used := make([]bool, len(fields), context.temp_allocator) use_field_idx := -1 diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index b77ae97b3..f5523c299 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -33,6 +33,7 @@ import "core:intrinsics" import "core:mem" import "core:os" import "core:strings" +import "core:runtime" likely :: intrinsics.expect @@ -408,7 +409,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha next := scan(t) #partial switch next.kind { case .Ident: - if len(next.text) == 3 && strings.to_lower(next.text, context.temp_allocator) == "xml" { + if len(next.text) == 3 && strings.equal_fold(next.text, "xml") { parse_prologue(doc) or_return } else if len(doc.prologue) > 0 { /* @@ -614,6 +615,7 @@ parse_prologue :: proc(doc: ^Document) -> (err: Error) { } case "encoding": + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() switch strings.to_lower(attr.val, context.temp_allocator) { case "utf-8", "utf8": doc.encoding = .UTF_8 diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin index 18545092d..70eb3567e 100644 --- a/core/image/netpbm/netpbm.odin +++ b/core/image/netpbm/netpbm.odin @@ -8,6 +8,7 @@ import "core:os" import "core:strconv" import "core:strings" import "core:unicode" +import "core:runtime" Image :: image.Image Format :: image.Netpbm_Format @@ -407,6 +408,8 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head } length = header_end_index + len(HEADER_END) + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) + // string buffer for the tupltype tupltype: strings.Builder strings.builder_init(&tupltype, context.temp_allocator); defer strings.builder_destroy(&tupltype) diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin index 0ebf0b20b..bfe56d62e 100644 --- a/core/image/png/helpers.odin +++ b/core/image/png/helpers.odin @@ -16,6 +16,7 @@ import coretime "core:time" import "core:strings" import "core:bytes" import "core:mem" +import "core:runtime" /* Cleanup of image-specific data. @@ -91,6 +92,8 @@ core_time :: proc(c: image.PNG_Chunk) -> (t: coretime.Time, ok: bool) { } text :: proc(c: image.PNG_Chunk) -> (res: Text, ok: bool) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) + assert(len(c.data) == int(c.header.length)) #partial switch c.header.type { case .tEXt: @@ -194,18 +197,18 @@ text_destroy :: proc(text: Text) { } iccp :: proc(c: image.PNG_Chunk) -> (res: iCCP, ok: bool) { - ok = true + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator) if len(fields[0]) < 1 || len(fields[0]) > 79 { // Invalid profile name - ok = false; return + return } if len(fields[1]) != 0 { // Compression method should be a zero, which the split turned into an empty slice. - ok = false; return + return } // Set up ZLIB context and decompress iCCP payload @@ -213,12 +216,12 @@ iccp :: proc(c: image.PNG_Chunk) -> (res: iCCP, ok: bool) { zlib_error := zlib.inflate_from_byte_array(fields[2], &buf) if zlib_error != nil { bytes.buffer_destroy(&buf) - ok = false; return + return } res.name = strings.clone(string(fields[0])) res.profile = bytes.buffer_to_bytes(&buf) - + ok = true return } @@ -256,18 +259,18 @@ plte :: proc(c: image.PNG_Chunk) -> (res: PLTE, ok: bool) { splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) { if c.header.type != .sPLT { - return {}, false + return } - ok = true + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=2, allocator=context.temp_allocator) if len(fields) != 2 { - return {}, false + return } res.depth = fields[1][0] if res.depth != 8 && res.depth != 16 { - return {}, false + return } data := fields[1][1:] @@ -275,21 +278,21 @@ splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) { if res.depth == 8 { if len(data) % 6 != 0 { - return {}, false + return } count = len(data) / 6 if count > 256 { - return {}, false + return } res.entries = mem.slice_data_cast([][4]u8, data) } else { // res.depth == 16 if len(data) % 10 != 0 { - return {}, false + return } count = len(data) / 10 if count > 256 { - return {}, false + return } res.entries = mem.slice_data_cast([][4]u16, data) @@ -297,7 +300,7 @@ splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) { res.name = strings.clone(string(fields[0])) res.used = u16(count) - + ok = true return } diff --git a/core/image/png/png.odin b/core/image/png/png.odin index 3faa39c83..02983997c 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -23,6 +23,7 @@ import "core:bytes" import "core:io" import "core:mem" import "core:intrinsics" +import "core:runtime" // Limit chunk sizes. // By default: IDAT = 8k x 8k x 16-bits + 8k filter bytes. @@ -1247,6 +1248,8 @@ defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) { // TODO: See about doing a Duff's #unroll where practicable + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + // Apron so we don't need to special case first rows. up := make([]u8, row_stride, context.temp_allocator) ok = true @@ -1299,10 +1302,9 @@ defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) { } // @(optimization_mode="speed") -defilter_less_than_8 :: proc(params: ^Filter_Params) -> (ok: bool) #no_bounds_check { +defilter_less_than_8 :: proc(params: ^Filter_Params) -> bool #no_bounds_check { using params - ok = true row_stride_in := ((channels * width * depth) + 7) >> 3 row_stride_out := channels * width @@ -1314,6 +1316,8 @@ defilter_less_than_8 :: proc(params: ^Filter_Params) -> (ok: bool) #no_bounds_ch // TODO: See about doing a Duff's #unroll where practicable + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + // Apron so we don't need to special case first rows. up := make([]u8, row_stride_out, context.temp_allocator) @@ -1457,18 +1461,18 @@ defilter_less_than_8 :: proc(params: ^Filter_Params) -> (ok: bool) #no_bounds_ch } } - return + return true } // @(optimization_mode="speed") -defilter_16 :: proc(params: ^Filter_Params) -> (ok: bool) { - +defilter_16 :: proc(params: ^Filter_Params) -> bool { using params - ok = true stride := channels * 2 row_stride := width * stride + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + // TODO: See about doing a Duff's #unroll where practicable // Apron so we don't need to special case first rows. up := make([]u8, row_stride, context.temp_allocator) @@ -1518,7 +1522,7 @@ defilter_16 :: proc(params: ^Filter_Params) -> (ok: bool) { dest = dest[row_stride:] } - return + return true } defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IHDR, options: Options) -> (err: Error) { diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index cf5dc0764..f93138d07 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -148,12 +148,12 @@ arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_locat } } -arena_free_all :: proc(arena: ^Arena) { +arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { switch arena.kind { case .Growing: sync.mutex_guard(&arena.mutex) for arena.curr_block != nil { - arena_growing_free_last_memory_block(arena) + arena_growing_free_last_memory_block(arena, loc) } arena.total_reserved = 0 case .Static, .Buffer: @@ -240,17 +240,17 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, switch mode { case .Alloc, .Alloc_Non_Zeroed: - return arena_alloc(arena, size, alignment) + return arena_alloc(arena, size, alignment, location) case .Free: err = .Mode_Not_Implemented case .Free_All: - arena_free_all(arena) + arena_free_all(arena, location) case .Resize: old_data := ([^]byte)(old_memory) switch { case old_data == nil: - return arena_alloc(arena, size, alignment) + return arena_alloc(arena, size, alignment, location) case size == old_size: // return old memory data = old_data[:size] @@ -264,7 +264,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, return } - new_memory := arena_alloc(arena, size, alignment) or_return + new_memory := arena_alloc(arena, size, alignment, location) or_return if new_memory == nil { return } diff --git a/core/os/dir_freebsd.odin b/core/os/dir_freebsd.odin index c664ffb34..2965182cd 100644 --- a/core/os/dir_freebsd.odin +++ b/core/os/dir_freebsd.odin @@ -50,7 +50,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F continue } - fullpath := make([]byte, len(dirpath)+1+len(filename)) + fullpath := make([]byte, len(dirpath)+1+len(filename), context.temp_allocator) copy(fullpath, dirpath) copy(fullpath[len(dirpath):], "/") copy(fullpath[len(dirpath)+1:], filename) diff --git a/core/os/dir_linux.odin b/core/os/dir_linux.odin index 74c410a51..4971fa9d5 100644 --- a/core/os/dir_linux.odin +++ b/core/os/dir_linux.odin @@ -2,6 +2,7 @@ package os import "core:strings" import "core:mem" +import "core:runtime" read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { dirp: Dir @@ -51,6 +52,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F continue } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) defer delete(fullpath, context.temp_allocator) diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index 9333548cf..531a5cd82 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -2,6 +2,7 @@ package os import win32 "core:sys/windows" import "core:strings" +import "core:runtime" read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) { @@ -65,13 +66,16 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F n = -1 size = 100 } - dfi := make([dynamic]File_Info, 0, size) + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) wpath: []u16 - wpath, err = cleanpath_from_handle_u16(fd) + wpath, err = cleanpath_from_handle_u16(fd, context.temp_allocator) if len(wpath) == 0 || err != ERROR_NONE { return } + + dfi := make([dynamic]File_Info, 0, size) + wpath_search := make([]u16, len(wpath)+3, context.temp_allocator) copy(wpath_search, wpath) wpath_search[len(wpath)+0] = '\\' diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index 6e14127ed..ff20f126a 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -1,6 +1,7 @@ package os import win32 "core:sys/windows" +import "core:runtime" // lookup_env gets the value of the environment variable named by the key // If the variable is found in the environment the value (which can be empty) is returned and the boolean is true @@ -18,6 +19,8 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin return "", false } } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) + b := make([dynamic]u16, n, context.temp_allocator) n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b))) if n == 0 { @@ -87,6 +90,7 @@ environ :: proc(allocator := context.allocator) -> []string { // clear_env deletes all environment variables clear_env :: proc() { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() envs := environ(context.temp_allocator) for env in envs { for j in 1.. bool { @@ -327,6 +328,7 @@ get_std_handle :: proc "contextless" (h: uint) -> Handle { exists :: proc(path: string) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wpath := win32.utf8_to_wstring(path, context.temp_allocator) attribs := win32.GetFileAttributesW(wpath) @@ -334,6 +336,7 @@ exists :: proc(path: string) -> bool { } is_file :: proc(path: string) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wpath := win32.utf8_to_wstring(path, context.temp_allocator) attribs := win32.GetFileAttributesW(wpath) @@ -344,6 +347,7 @@ is_file :: proc(path: string) -> bool { } is_dir :: proc(path: string) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wpath := win32.utf8_to_wstring(path, context.temp_allocator) attribs := win32.GetFileAttributesW(wpath) @@ -359,6 +363,8 @@ is_dir :: proc(path: string) -> bool { get_current_directory :: proc(allocator := context.allocator) -> string { win32.AcquireSRWLockExclusive(&cwd_lock) + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) + sz_utf16 := win32.GetCurrentDirectoryW(0, nil) dir_buf_wstr := make([]u16, sz_utf16, context.temp_allocator) // the first time, it _includes_ the NUL. @@ -387,6 +393,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { change_directory :: proc(path: string) -> (err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.SetCurrentDirectoryW(wpath) { @@ -396,6 +403,7 @@ change_directory :: proc(path: string) -> (err: Errno) { } make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() // Mode is unused on Windows, but is needed on *nix wpath := win32.utf8_to_wstring(path, context.temp_allocator) @@ -407,6 +415,7 @@ make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) { remove_directory :: proc(path: string) -> (err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.RemoveDirectoryW(wpath) { @@ -479,12 +488,14 @@ fix_long_path :: proc(path: string) -> string { link :: proc(old_name, new_name: string) -> (err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() n := win32.utf8_to_wstring(fix_long_path(new_name)) o := win32.utf8_to_wstring(fix_long_path(old_name)) return Errno(win32.CreateHardLinkW(n, o, nil)) } unlink :: proc(path: string) -> (err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.DeleteFileW(wpath) { @@ -496,6 +507,7 @@ unlink :: proc(path: string) -> (err: Errno) { rename :: proc(old_path, new_path: string) -> (err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() from := win32.utf8_to_wstring(old_path, context.temp_allocator) to := win32.utf8_to_wstring(new_path, context.temp_allocator) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 1257a3d7b..1a6f69d31 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -39,10 +39,8 @@ _file_allocator :: proc() -> runtime.Allocator { } _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error) { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + name_cstr := _name_to_cstring(name) flags_i: int switch flags & O_RDONLY|O_WRONLY|O_RDWR { @@ -411,12 +409,7 @@ _is_dir_fd :: proc(fd: int) -> bool { // defined as 512, however, it is well known that paths can exceed that limit. // So, in theory you could have a path larger than the entire temp_allocator's // buffer. Therefor, any large paths will use context.allocator. -_name_to_cstring :: proc(name: string) -> (cname: cstring, allocated: bool) { - if len(name) > _CSTRING_NAME_HEAP_THRESHOLD { - cname = strings.clone_to_cstring(name) - allocated = true - return - } - cname = strings.clone_to_cstring(name, context.temp_allocator) - return +@(private="file") +_temp_name_to_cstring :: proc(name: string) -> (cname: cstring) { + return strings.clone_to_cstring(name, context.temp_allocator) } diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index e08c9005a..c16cf737e 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -355,6 +355,7 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno flags = O_RDONLY } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, i32(flags), u16(mode)) if handle == -1 { @@ -516,24 +517,28 @@ is_file :: proc {is_file_path, is_file_handle} is_dir :: proc {is_dir_path, is_dir_handle} exists :: proc(path: string) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_access(cpath, O_RDONLY) return res == 0 } rename :: proc(old: string, new: string) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() old_cstr := strings.clone_to_cstring(old, context.temp_allocator) new_cstr := strings.clone_to_cstring(new, context.temp_allocator) return _unix_rename(old_cstr, new_cstr) != -1 } remove :: proc(path: string) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) return _unix_remove(path_cstr) != -1 } @private _stat :: proc(path: string) -> (OS_Stat, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) s: OS_Stat @@ -546,6 +551,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { @private _lstat :: proc(path: string) -> (OS_Stat, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) s: OS_Stat @@ -611,6 +617,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) @private _readlink :: proc(path: string) -> (string, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) bufsz : uint = 256 @@ -648,6 +655,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { rel = "." } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator) path_ptr := _unix_realpath(rel_cstr, nil) @@ -663,6 +671,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } access :: proc(path: string, mask: int) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) return _unix_access(cstr, mask) == 0 } @@ -687,6 +696,7 @@ heap_free :: proc(ptr: rawptr) { } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) cstr := _unix_getenv(path_str) if cstr == nil { @@ -718,6 +728,7 @@ get_current_directory :: proc() -> string { } set_current_directory :: proc(path: string) -> (err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 { @@ -727,6 +738,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { } make_directory :: proc(path: string, mode: u16 = 0o775) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { @@ -751,12 +763,14 @@ current_thread_id :: proc "contextless" () -> int { } dlopen :: proc(filename: string, flags: int) -> rawptr { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(filename, context.temp_allocator) handle := _unix_dlopen(cstr, flags) return handle } dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil) + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(symbol, context.temp_allocator) proc_handle := _unix_dlsym(handle, cstr) return proc_handle diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 0ab48efaf..c2ea82bf5 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -309,6 +309,7 @@ get_last_error :: proc "contextless" () -> int { } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { @@ -361,6 +362,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { } rename :: proc(old_path, new_path: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) res := _unix_rename(old_path_cstr, new_path_cstr) @@ -371,6 +373,7 @@ rename :: proc(old_path, new_path: string) -> Errno { } remove :: proc(path: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_unlink(path_cstr) if res == -1 { @@ -380,6 +383,7 @@ remove :: proc(path: string) -> Errno { } make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { @@ -389,6 +393,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { } remove_directory :: proc(path: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_rmdir(path_cstr) if res == -1 { @@ -474,6 +479,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { @private _stat :: proc(path: string) -> (OS_Stat, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) s: OS_Stat = --- result := _unix_lstat(cstr, &s) @@ -485,6 +491,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { @private _lstat :: proc(path: string) -> (OS_Stat, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) // deliberately uninitialized @@ -550,6 +557,8 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) @private _readlink :: proc(path: string) -> (string, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) bufsz : uint = MAX_PATH @@ -567,7 +576,8 @@ _readlink :: proc(path: string) -> (string, Errno) { return strings.string_from_ptr(&buf[0], rc), ERROR_NONE } } - unreachable() + + return "", Errno{} } // XXX FreeBSD @@ -580,6 +590,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { if rel == "" { rel = "." } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator) @@ -596,6 +607,8 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } access :: proc(path: string, mask: int) -> (bool, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + cstr := strings.clone_to_cstring(path, context.temp_allocator) result := _unix_access(cstr, c.int(mask)) if result == -1 { @@ -626,6 +639,8 @@ heap_free :: proc(ptr: rawptr) { } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) + path_str := strings.clone_to_cstring(key, context.temp_allocator) cstr := _unix_getenv(path_str) if cstr == nil { @@ -660,6 +675,7 @@ get_current_directory :: proc() -> string { } set_current_directory :: proc(path: string) -> (err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 do return Errno(get_last_error()) @@ -676,12 +692,14 @@ current_thread_id :: proc "contextless" () -> int { } dlopen :: proc(filename: string, flags: int) -> rawptr { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(filename, context.temp_allocator) handle := _unix_dlopen(cstr, c.int(flags)) return handle } dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil) + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(symbol, context.temp_allocator) proc_handle := _unix_dlsym(handle, cstr) return proc_handle diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index cef394b95..237e3495c 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -346,7 +346,9 @@ execvp :: proc(path: string, args: []string) -> Errno { return Errno(get_last_error()) } + open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0o000) -> (Handle, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := unix.sys_open(cstr, flags, uint(mode)) if handle < 0 { @@ -425,22 +427,26 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { } rename :: proc(old_path, new_path: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) return _get_errno(unix.sys_rename(old_path_cstr, new_path_cstr)) } remove :: proc(path: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) return _get_errno(unix.sys_unlink(path_cstr)) } make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) return _get_errno(unix.sys_mkdir(path_cstr, uint(mode))) } remove_directory :: proc(path: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) return _get_errno(unix.sys_rmdir(path_cstr)) } @@ -494,6 +500,7 @@ is_file :: proc {is_file_path, is_file_handle} is_dir :: proc {is_dir_path, is_dir_handle} exists :: proc(path: string) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath := strings.clone_to_cstring(path, context.temp_allocator) res := unix.sys_access(cpath, O_RDONLY) return res == 0 @@ -529,6 +536,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { @private _stat :: proc(path: string) -> (OS_Stat, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) // deliberately uninitialized; the syscall fills this buffer for us @@ -542,6 +550,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { @private _lstat :: proc(path: string) -> (OS_Stat, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) // deliberately uninitialized; the syscall fills this buffer for us @@ -609,6 +618,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) @private _readlink :: proc(path: string) -> (string, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) bufsz : uint = 256 @@ -644,6 +654,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { if rel == "" { rel = "." } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator) @@ -660,6 +671,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } access :: proc(path: string, mask: int) -> (bool, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) result := unix.sys_access(cstr, mask) if result < 0 { @@ -690,6 +702,7 @@ heap_free :: proc(ptr: rawptr) { } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) // NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults. cstr := _unix_getenv(path_str) @@ -705,6 +718,7 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string) } set_env :: proc(key, value: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() s := strings.concatenate({key, "=", value, "\x00"}, context.temp_allocator) res := _unix_putenv(strings.unsafe_string_to_cstring(s)) if res < 0 { @@ -714,6 +728,7 @@ set_env :: proc(key, value: string) -> Errno { } unset_env :: proc(key: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() s := strings.clone_to_cstring(key, context.temp_allocator) res := _unix_putenv(s) if res < 0 { @@ -744,6 +759,7 @@ get_current_directory :: proc() -> string { } set_current_directory :: proc(path: string) -> (err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := unix.sys_chdir(cstr) if res < 0 { @@ -762,12 +778,14 @@ current_thread_id :: proc "contextless" () -> int { } dlopen :: proc(filename: string, flags: int) -> rawptr { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(filename, context.temp_allocator) handle := _unix_dlopen(cstr, c.int(flags)) return handle } dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil) + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(symbol, context.temp_allocator) proc_handle := _unix_dlsym(handle, cstr) return proc_handle diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 75ad19c46..957873a0b 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -308,6 +308,7 @@ fork :: proc() -> (Pid, Errno) { } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, c.int(flags), c.int(mode)) if handle == -1 { @@ -360,6 +361,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { } rename :: proc(old_path, new_path: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) res := _unix_rename(old_path_cstr, new_path_cstr) @@ -370,6 +372,7 @@ rename :: proc(old_path, new_path: string) -> Errno { } remove :: proc(path: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_unlink(path_cstr) if res == -1 { @@ -379,6 +382,7 @@ remove :: proc(path: string) -> Errno { } make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_mkdir(path_cstr, mode) if res == -1 { @@ -388,6 +392,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { } remove_directory :: proc(path: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_rmdir(path_cstr) if res == -1 { @@ -473,6 +478,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { @private _stat :: proc(path: string) -> (OS_Stat, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) // deliberately uninitialized @@ -486,6 +492,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { @private _lstat :: proc(path: string) -> (OS_Stat, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) // deliberately uninitialized @@ -552,6 +559,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) @private _readlink :: proc(path: string) -> (string, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) path_cstr := strings.clone_to_cstring(path, context.temp_allocator) bufsz : uint = MAX_PATH @@ -569,7 +577,6 @@ _readlink :: proc(path: string) -> (string, Errno) { return strings.string_from_ptr(&buf[0], rc), ERROR_NONE } } - unreachable() } // XXX OpenBSD @@ -583,6 +590,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { rel = "." } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator) path_ptr := _unix_realpath(rel_cstr, nil) @@ -598,6 +606,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } access :: proc(path: string, mask: int) -> (bool, Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_access(cstr, c.int(mask)) if res == -1 { @@ -628,6 +637,7 @@ heap_free :: proc(ptr: rawptr) { } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) cstr := _unix_getenv(path_str) if cstr == nil { @@ -658,6 +668,7 @@ get_current_directory :: proc() -> string { } set_current_directory :: proc(path: string) -> (err: Errno) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) if res == -1 { @@ -676,12 +687,14 @@ current_thread_id :: proc "contextless" () -> int { } dlopen :: proc(filename: string, flags: int) -> rawptr { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(filename, context.temp_allocator) handle := _unix_dlopen(cstr, c.int(flags)) return handle } dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil) + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(symbol, context.temp_allocator) proc_handle := _unix_dlsym(handle, cstr) return proc_handle diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index f6d8b3997..7b4c2f6c2 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -134,6 +134,7 @@ _processor_core_count :: proc() -> int { thread_count := 0 if !result && win32.GetLastError() == 122 && length > 0 { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() processors := make([]win32.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, length, context.temp_allocator) result = win32.GetLogicalProcessorInformation(&processors[0], &length) diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index c63fb4cf0..efea329ce 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -1,6 +1,7 @@ package os import "core:time" +import "core:runtime" import win32 "core:sys/windows" @(private) @@ -11,6 +12,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa if name == "" { name = "." } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) p := win32.utf8_to_utf16(name, context.temp_allocator) buf := make([dynamic]u16, 100) defer delete(buf) @@ -36,6 +38,7 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al context.allocator = allocator + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) wname := win32.utf8_to_wstring(fix_long_path(name), context.temp_allocator) fa: win32.WIN32_FILE_ATTRIBUTE_DATA @@ -132,14 +135,15 @@ cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 { @(private) cleanpath_from_handle :: proc(fd: Handle) -> (string, Errno) { - buf, err := cleanpath_from_handle_u16(fd) + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) + buf, err := cleanpath_from_handle_u16(fd, context.temp_allocator) if err != 0 { return "", err } return win32.utf16_to_utf8(buf, context.allocator) or_else "", err } @(private) -cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) { +cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ([]u16, Errno) { if fd == 0 { return nil, ERROR_INVALID_HANDLE } @@ -149,7 +153,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) { if n == 0 { return nil, Errno(win32.GetLastError()) } - buf := make([]u16, max(n, win32.DWORD(260))+1, context.temp_allocator) + buf := make([]u16, max(n, win32.DWORD(260))+1, allocator) buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0) return buf[:buf_len], ERROR_NONE } diff --git a/core/path/filepath/path_unix.odin b/core/path/filepath/path_unix.odin index 8faf6097c..898f34b6a 100644 --- a/core/path/filepath/path_unix.odin +++ b/core/path/filepath/path_unix.odin @@ -7,6 +7,7 @@ when ODIN_OS == .Darwin { foreign import libc "system:c" } +import "core:runtime" import "core:strings" SEPARATOR :: '/' @@ -41,6 +42,7 @@ abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { join :: proc(elems: []string, allocator := context.allocator) -> string { for e, i in elems { if e != "" { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) p := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) return clean(p, allocator) } diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin index cdfe3ddbb..e7dd4ab3e 100644 --- a/core/path/filepath/path_windows.odin +++ b/core/path/filepath/path_windows.odin @@ -1,6 +1,7 @@ package filepath import "core:strings" +import "core:runtime" import "core:os" import win32 "core:sys/windows" @@ -60,25 +61,25 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Errno) { } p := win32.utf8_to_utf16(name, ta) - buf := make([dynamic]u16, 100, ta) - for { - n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) - if n == 0 { - delete(buf) - return "", os.Errno(win32.GetLastError()) - } - if n <= u32(len(buf)) { - return win32.utf16_to_utf8(buf[:n], ta) or_else "", os.ERROR_NONE - } - resize(&buf, len(buf)*2) + n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil) + if n == 0 { + return "", os.Errno(win32.GetLastError()) } - return + buf := make([]u16, n, ta) + n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) + if n == 0 { + delete(buf) + return "", os.Errno(win32.GetLastError()) + } + + return win32.utf16_to_utf8(buf[:n], ta) or_else "", os.ERROR_NONE } abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator) full_path, err := temp_full_path(path) if err != 0 { return "", false @@ -99,6 +100,8 @@ join :: proc(elems: []string, allocator := context.allocator) -> string { join_non_empty :: proc(elems: []string, allocator := context.allocator) -> string { context.allocator = allocator + + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator) if len(elems[0]) == 2 && elems[0][1] == ':' { i := 1 diff --git a/core/path/slashpath/path.odin b/core/path/slashpath/path.odin index 865f619bf..5f5ab2ae9 100644 --- a/core/path/slashpath/path.odin +++ b/core/path/slashpath/path.odin @@ -5,6 +5,7 @@ // To manipulate operating system specific paths, use the path/filepath package package slashpath +import "core:runtime" import "core:strings" // is_separator checks whether the byte is a valid separator character @@ -150,8 +151,9 @@ join :: proc(elems: []string, allocator := context.allocator) -> string { context.allocator = allocator for elem, i in elems { if elem != "" { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) s := strings.join(elems[i:], "/", context.temp_allocator) - return clean(s) + return clean(s, allocator) } } return "" diff --git a/core/runtime/default_allocators_arena.odin b/core/runtime/default_allocators_arena.odin new file mode 100644 index 000000000..1c36c4f7c --- /dev/null +++ b/core/runtime/default_allocators_arena.odin @@ -0,0 +1,304 @@ +package runtime + +import "core:intrinsics" + +DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: uint(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE) + +Memory_Block :: struct { + prev: ^Memory_Block, + allocator: Allocator, + base: [^]byte, + used: uint, + capacity: uint, +} + +Arena :: struct { + backing_allocator: Allocator, + curr_block: ^Memory_Block, + total_used: uint, + total_capacity: uint, + minimum_block_size: uint, + temp_count: uint, +} + +@(private, require_results) +safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) { + z, did_overflow := intrinsics.overflow_add(x, y) + return z, !did_overflow +} + +@(require_results) +memory_block_alloc :: proc(allocator: Allocator, capacity: uint, loc := #caller_location) -> (block: ^Memory_Block, err: Allocator_Error) { + total_size := uint(capacity + size_of(Memory_Block)) + base_offset := uintptr(size_of(Memory_Block)) + + min_alignment: int = max(16, align_of(Memory_Block)) + data := mem_alloc(int(total_size), min_alignment, allocator, loc) or_return + block = (^Memory_Block)(raw_data(data)) + end := uintptr(raw_data(data)[len(data):]) + + block.allocator = allocator + block.base = ([^]byte)(uintptr(block) + base_offset) + block.capacity = uint(end - uintptr(block.base)) + + // Should be zeroed + assert(block.used == 0) + assert(block.prev == nil) + return +} + +memory_block_dealloc :: proc(block_to_free: ^Memory_Block, loc := #caller_location) { + if block_to_free != nil { + allocator := block_to_free.allocator + mem_free(block_to_free, allocator, loc) + } +} + +@(require_results) +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:]) + mask := alignment-1 + if ptr & mask != 0 { + alignment_offset = uint(alignment - (ptr & mask)) + } + return alignment_offset + + } + if block == nil { + return nil, .Out_Of_Memory + } + alignment_offset := calc_alignment_offset(block, uintptr(alignment)) + size, size_ok := safe_add(min_size, alignment_offset) + if !size_ok { + err = .Out_Of_Memory + return + } + + if to_be_used, ok := safe_add(block.used, size); !ok || to_be_used > block.capacity { + err = .Out_Of_Memory + return + } + data = block.base[block.used+alignment_offset:][:min_size] + block.used += size + return +} + +@(require_results) +arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { + align_forward_uint :: proc "contextless" (ptr, align: uint) -> uint { + p := ptr + modulo := p & (align-1) + if modulo != 0 { + p += align - modulo + } + return p + } + + assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc) + + size := size + if size == 0 { + return + } + + if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.capacity { + size = 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) + + if arena.backing_allocator.procedure == nil { + arena.backing_allocator = default_allocator() + } + + new_block := memory_block_alloc(arena.backing_allocator, block_size, loc) or_return + new_block.prev = arena.curr_block + arena.curr_block = new_block + arena.total_capacity += new_block.capacity + } + + 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 + return +} + +// `arena_init` will initialize the arena with a usuable block. +// This procedure is not necessary to use the Arena as the default zero as `arena_alloc` will set things up if necessary +@(require_results) +arena_init :: proc(arena: ^Arena, size: uint, backing_allocator: Allocator, loc := #caller_location) -> Allocator_Error { + arena^ = {} + arena.backing_allocator = backing_allocator + arena.minimum_block_size = max(size, 1<<12) // minimum block size of 4 KiB + new_block := memory_block_alloc(arena.backing_allocator, arena.minimum_block_size, loc) or_return + arena.curr_block = new_block + arena.total_capacity += new_block.capacity + return nil +} + + +arena_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) { + if free_block := arena.curr_block; free_block != nil { + arena.curr_block = free_block.prev + + arena.total_capacity -= free_block.capacity + memory_block_dealloc(free_block, loc) + } +} + +// `arena_free_all` will free all but the first memory block, and then reset the memory block +arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { + for arena.curr_block != nil && arena.curr_block.prev != nil { + arena_free_last_memory_block(arena, loc) + } + + if arena.curr_block != nil { + intrinsics.mem_zero(arena.curr_block.base, arena.curr_block.used) + arena.curr_block.used = 0 + } + arena.total_used = 0 +} + +arena_destroy :: proc(arena: ^Arena, loc := #caller_location) { + for arena.curr_block != nil { + free_block := arena.curr_block + arena.curr_block = free_block.prev + + arena.total_capacity -= free_block.capacity + memory_block_dealloc(free_block, loc) + } + arena.total_used = 0 + arena.total_capacity = 0 +} + +arena_allocator :: proc(arena: ^Arena) -> Allocator { + return Allocator{arena_allocator_proc, arena} +} + +arena_allocator_proc :: proc(allocator_data: rawptr, mode: 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, .Alloc_Non_Zeroed: + return arena_alloc(arena, size, alignment, location) + case .Free: + err = .Mode_Not_Implemented + case .Free_All: + arena_free_all(arena, location) + case .Resize: + old_data := ([^]byte)(old_memory) + + switch { + case old_data == nil: + return arena_alloc(arena, size, alignment, location) + 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, location) or_return + if new_memory == nil { + return + } + copy(new_memory, old_data[:old_size]) + return new_memory, nil + case .Query_Features: + set := (^Allocator_Mode_Set)(old_memory) + if set != nil { + set^ = {.Alloc, .Alloc_Non_Zeroed, .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) { + if temp.arena == nil { + assert(temp.block == nil) + assert(temp.used == 0) + return + } + arena := temp.arena + + if temp.block != nil { + 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_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.capacity-block.used) + intrinsics.mem_zero(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 +} + +// Ignore the use of a `arena_temp_begin` entirely +arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) { + assert(temp.arena != nil, "nil arena", loc) + arena := temp.arena + + 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/runtime/default_temporary_allocator.odin b/core/runtime/default_temporary_allocator.odin index 9cc17584a..296ead722 100644 --- a/core/runtime/default_temporary_allocator.odin +++ b/core/runtime/default_temporary_allocator.odin @@ -6,154 +6,33 @@ DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKIN when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR { Default_Temp_Allocator :: struct {} - default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {} + default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {} default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {} default_temp_allocator_proc :: nil_allocator_proc + + @(require_results) + default_temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: Arena_Temp) { + return + } + + default_temp_allocator_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) { + } } else { Default_Temp_Allocator :: struct { - data: []byte, - curr_offset: int, - prev_allocation: rawptr, - backup_allocator: Allocator, - leaked_allocations: [dynamic][]byte, + arena: Arena, } - default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) { - s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator) - s.curr_offset = 0 - s.prev_allocation = nil - s.backup_allocator = backup_allocator - s.leaked_allocations.allocator = backup_allocator + default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) { + _ = arena_init(&s.arena, uint(size), backing_allocator) } default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) { - if s == nil { - return + if s != nil { + arena_destroy(&s.arena) + s^ = {} } - for ptr in s.leaked_allocations { - free(raw_data(ptr), s.backup_allocator) - } - delete(s.leaked_allocations) - delete(s.data, s.backup_allocator) - s^ = {} - } - - @(private) - default_temp_allocator_alloc :: proc(s: ^Default_Temp_Allocator, size, alignment: int, loc := #caller_location) -> ([]byte, Allocator_Error) { - size := size - size = align_forward_int(size, alignment) - - switch { - case s.curr_offset+size <= len(s.data): - start := uintptr(raw_data(s.data)) - ptr := start + uintptr(s.curr_offset) - ptr = align_forward_uintptr(ptr, uintptr(alignment)) - mem_zero(rawptr(ptr), size) - - s.prev_allocation = rawptr(ptr) - offset := int(ptr - start) - s.curr_offset = offset + size - return byte_slice(rawptr(ptr), size), .None - - case size <= len(s.data): - start := uintptr(raw_data(s.data)) - ptr := align_forward_uintptr(start, uintptr(alignment)) - mem_zero(rawptr(ptr), size) - - s.prev_allocation = rawptr(ptr) - offset := int(ptr - start) - s.curr_offset = offset + size - return byte_slice(rawptr(ptr), size), .None - } - a := s.backup_allocator - if a.procedure == nil { - a = context.allocator - s.backup_allocator = a - } - - data, err := mem_alloc_bytes(size, alignment, a, loc) - if err != nil { - return data, err - } - if s.leaked_allocations == nil { - s.leaked_allocations = make([dynamic][]byte, a) - } - append(&s.leaked_allocations, data) - - // TODO(bill): Should leaks be notified about? - if logger := context.logger; logger.lowest_level <= .Warning { - if logger.procedure != nil { - logger.procedure(logger.data, .Warning, "default temp allocator resorted to backup_allocator" , logger.options, loc) - } - } - - return data, .None - } - - @(private) - default_temp_allocator_free :: proc(s: ^Default_Temp_Allocator, old_memory: rawptr, loc := #caller_location) -> Allocator_Error { - if old_memory == nil { - return .None - } - - start := uintptr(raw_data(s.data)) - end := start + uintptr(len(s.data)) - old_ptr := uintptr(old_memory) - - if s.prev_allocation == old_memory { - s.curr_offset = int(uintptr(s.prev_allocation) - start) - s.prev_allocation = nil - return .None - } - - if start <= old_ptr && old_ptr < end { - // NOTE(bill): Cannot free this pointer but it is valid - return .None - } - - if len(s.leaked_allocations) != 0 { - for data, i in s.leaked_allocations { - ptr := raw_data(data) - if ptr == old_memory { - free(ptr, s.backup_allocator) - ordered_remove(&s.leaked_allocations, i) - return .None - } - } - } - return .Invalid_Pointer - // panic("invalid pointer passed to default_temp_allocator"); - } - - @(private) - default_temp_allocator_free_all :: proc(s: ^Default_Temp_Allocator, loc := #caller_location) { - s.curr_offset = 0 - s.prev_allocation = nil - for data in s.leaked_allocations { - free(raw_data(data), s.backup_allocator) - } - clear(&s.leaked_allocations) - } - - @(private) - default_temp_allocator_resize :: proc(s: ^Default_Temp_Allocator, old_memory: rawptr, old_size, size, alignment: int, loc := #caller_location) -> ([]byte, Allocator_Error) { - begin := uintptr(raw_data(s.data)) - end := begin + uintptr(len(s.data)) - old_ptr := uintptr(old_memory) - if old_memory == s.prev_allocation && old_ptr & uintptr(alignment)-1 == 0 { - if old_ptr+uintptr(size) < end { - s.curr_offset = int(old_ptr-begin)+size - return byte_slice(old_memory, size), .None - } - } - data, err := default_temp_allocator_alloc(s, size, alignment, loc) - if err == .None { - copy(data, byte_slice(old_memory, old_size)) - err = default_temp_allocator_free(s, old_memory, loc) - } - return data, err } default_temp_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, @@ -161,41 +40,36 @@ when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { s := (^Default_Temp_Allocator)(allocator_data) + return arena_allocator_proc(&s.arena, mode, size, alignment, old_memory, old_size, loc) + } - if s.data == nil { - default_temp_allocator_init(s, DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, default_allocator()) + @(require_results) + default_temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: Arena_Temp) { + if context.temp_allocator.data == &global_default_temp_allocator_data { + temp = arena_temp_begin(&global_default_temp_allocator_data.arena, loc) } - - switch mode { - case .Alloc, .Alloc_Non_Zeroed: - data, err = default_temp_allocator_alloc(s, size, alignment, loc) - case .Free: - err = default_temp_allocator_free(s, old_memory, loc) - - case .Free_All: - default_temp_allocator_free_all(s, loc) - - case .Resize: - data, err = default_temp_allocator_resize(s, old_memory, old_size, size, alignment, loc) - - case .Query_Features: - set := (^Allocator_Mode_Set)(old_memory) - if set != nil { - set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features} - } - - case .Query_Info: - return nil, .Mode_Not_Implemented - } - return } + + default_temp_allocator_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) { + arena_temp_end(temp, loc) + } } +@(deferred_out=default_temp_allocator_temp_end) +DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD :: #force_inline proc(ignore := false, loc := #caller_location) -> (Arena_Temp, Source_Code_Location) { + if ignore { + return {}, loc + } else { + return default_temp_allocator_temp_begin(loc), loc + } +} + + default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator { return Allocator{ procedure = default_temp_allocator_proc, - data = allocator, + data = allocator, } } diff --git a/core/strings/strings.odin b/core/strings/strings.odin index ba357e027..29d9a6e66 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -5,6 +5,7 @@ import "core:io" import "core:mem" import "core:slice" import "core:unicode" +import "core:runtime" import "core:unicode/utf8" // returns a clone of the string `s` allocated using the `allocator` @@ -1425,7 +1426,9 @@ split_multi :: proc(s: string, substrs: []string, allocator := context.allocator // TODO maybe remove duplicate substrs // sort substrings by string size, largest to smallest + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() temp_substrs := slice.clone(substrs, context.temp_allocator) + defer delete(temp_substrs) slice.sort_by(temp_substrs, proc(a, b: string) -> bool { return len(a) > len(b) }) diff --git a/core/sys/darwin/xnu_system_call_helpers.odin b/core/sys/darwin/xnu_system_call_helpers.odin index 9522b9908..c225c77fb 100644 --- a/core/sys/darwin/xnu_system_call_helpers.odin +++ b/core/sys/darwin/xnu_system_call_helpers.odin @@ -97,6 +97,7 @@ clone_to_cstring :: proc(s: string, allocator: runtime.Allocator, loc := #caller sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, bool) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cmode: u32 = 0 cflags: u32 = 0 @@ -132,30 +133,35 @@ sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, b } sys_mkdir :: proc(path: string, mode: Permission) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath: cstring = clone_to_cstring(path, context.temp_allocator) cflags := _sys_permission_mode(mode) return syscall_mkdir(cpath, cflags) != -1 } sys_mkdir_at :: proc(fd: c.int, path: string, mode: Permission) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath: cstring = clone_to_cstring(path, context.temp_allocator) cflags := _sys_permission_mode(mode) return syscall_mkdir_at(fd, cpath, cflags) != -1 } sys_rmdir :: proc(path: string, mode: Permission) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath: cstring = clone_to_cstring(path, context.temp_allocator) cflags := _sys_permission_mode(mode) return syscall_rmdir(cpath, cflags) != -1 } sys_rename :: proc(path: string, new_path: string) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath: cstring = clone_to_cstring(path, context.temp_allocator) cnpath: cstring = clone_to_cstring(new_path, context.temp_allocator) return syscall_rename(cpath, cnpath) != -1 } sys_rename_at :: proc(fd: c.int, path: string, to_fd: c.int, new_path: string) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath: cstring = clone_to_cstring(path, context.temp_allocator) cnpath: cstring = clone_to_cstring(new_path, context.temp_allocator) return syscall_rename_at(fd, cpath, to_fd, cnpath) != -1 @@ -166,12 +172,14 @@ sys_lseek :: proc(fd: c.int, offset: i64, whence: Offset_From) -> i64 { } sys_chmod :: proc(path: string, mode: Permission) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath: cstring = clone_to_cstring(path, context.temp_allocator) cmode := _sys_permission_mode(mode) return syscall_chmod(cpath, cmode) != -1 } sys_lstat :: proc(path: string, status: ^stat) -> bool { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath: cstring = clone_to_cstring(path, context.temp_allocator) return syscall_lstat(cpath, status) != -1 } diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin index d226f668c..7a56f1e23 100644 --- a/core/sys/info/platform_darwin.odin +++ b/core/sys/info/platform_darwin.odin @@ -4,6 +4,7 @@ package sysinfo import sys "core:sys/unix" import "core:strconv" import "core:strings" +import "core:runtime" @(private) version_string_buf: [1024]u8 @@ -41,6 +42,8 @@ init_os_version :: proc () { major_ok, minor_ok, patch_ok: bool + tmp := runtime.default_temp_allocator_temp_begin() + triplet := strings.split(string(cstring(&version_bits[0])), ".", context.temp_allocator) if len(triplet) != 3 { have_kernel_version = false @@ -54,6 +57,8 @@ init_os_version :: proc () { } } + runtime.default_temp_allocator_temp_end(tmp) + if !have_kernel_version { // We don't know the kernel version, but we do know the build strings.write_string(&b, "macOS Unknown (build ") diff --git a/core/sys/info/platform_freebsd.odin b/core/sys/info/platform_freebsd.odin index 0ca2841be..1d53da998 100644 --- a/core/sys/info/platform_freebsd.odin +++ b/core/sys/info/platform_freebsd.odin @@ -4,6 +4,7 @@ package sysinfo import sys "core:sys/unix" import "core:strings" import "core:strconv" +import "core:runtime" @(private) version_string_buf: [1024]u8 @@ -47,6 +48,8 @@ init_os_version :: proc () { return } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + // Parse kernel version release := string(cstring(raw_data(kernel_version_buf[:]))) version_bits := strings.split_n(release, "-", 2, context.temp_allocator) diff --git a/core/sys/info/platform_linux.odin b/core/sys/info/platform_linux.odin index d1f9ca599..e9cc1dbc9 100644 --- a/core/sys/info/platform_linux.odin +++ b/core/sys/info/platform_linux.odin @@ -4,6 +4,7 @@ package sysinfo import "core:c" import sys "core:sys/unix" import "core:intrinsics" +import "core:runtime" import "core:os" import "core:strings" import "core:strconv" @@ -69,6 +70,8 @@ init_os_version :: proc () { l := strings.builder_len(b) strings.write_string(&b, string(cstring(&uts.release[0]))) + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + // Parse kernel version, as substrings of the version info in `version_string_buf` version_bits := strings.split_n(strings.to_string(b)[l:], "-", 2, context.temp_allocator) if len(version_bits) > 1 { diff --git a/core/sys/info/platform_openbsd.odin b/core/sys/info/platform_openbsd.odin index 080fad9b7..dbca6eaf3 100644 --- a/core/sys/info/platform_openbsd.odin +++ b/core/sys/info/platform_openbsd.odin @@ -4,6 +4,7 @@ package sysinfo import sys "core:sys/unix" import "core:strings" import "core:strconv" +import "core:runtime" @(private) version_string_buf: [1024]u8 @@ -32,7 +33,9 @@ init_os_version :: proc () { version := string(cstring(raw_data(kernel_version_buf[:]))) strings.write_string(&b, version) - // // Parse kernel version + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + // Parse kernel version triplet := strings.split(version, ".", context.temp_allocator) if len(triplet) == 2 { major, major_ok := strconv.parse_int(triplet[0]) diff --git a/core/sys/info/platform_windows.odin b/core/sys/info/platform_windows.odin index f7f689346..5e922d904 100644 --- a/core/sys/info/platform_windows.odin +++ b/core/sys/info/platform_windows.odin @@ -7,6 +7,7 @@ import "core:strings" import "core:unicode/utf16" import "core:fmt" +import "core:runtime" @(private) version_string_buf: [1024]u8 @@ -314,6 +315,8 @@ read_reg :: proc(hkey: sys.HKEY, subkey, val: string, $T: typeid) -> (res: T, ok return {}, false } + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator) val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 29a673980..b4836416e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6840,6 +6840,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c if (operand->mode == Addressing_Builtin) { i32 id = operand->builtin_id; + Entity *e = entity_of_node(operand->expr); + if (e != nullptr && e->token.string == "expand_to_tuple") { + warning(operand->expr, "'expand_to_tuple' has been replaced with 'expand_values'"); + } if (!check_builtin_procedure(c, operand, call, id, type_hint)) { operand->mode = Addressing_Invalid; operand->type = t_invalid; diff --git a/src/checker.cpp b/src/checker.cpp index 94bbb32e6..1bb437beb 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1070,6 +1070,13 @@ gb_internal void init_universal(void) { } } } + { + BuiltinProcId id = BuiltinProc_expand_values; + String name = str_lit("expand_to_tuple"); + Entity *entity = alloc_entity(Entity_Builtin, nullptr, make_token_ident(name), t_invalid); + entity->Builtin.id = id; + add_global_entity(entity, builtin_pkg->scope); + } bool defined_values_double_declaration = false; for (auto const &entry : bc->defined_values) {