diff --git a/core/log/log.odin b/core/log/log.odin index 76b8550e8..e6a22a3a1 100644 --- a/core/log/log.odin +++ b/core/log/log.odin @@ -1,7 +1,13 @@ package log +import "core:runtime" import "core:fmt" + +// NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle. + +Level :: runtime.Logger_Level; +/* Level :: enum { Debug, Info, @@ -9,7 +15,10 @@ Level :: enum { Error, Fatal, } +*/ +Option :: runtime.Logger_Option; +/* Option :: enum { Level, Date, @@ -20,8 +29,13 @@ Option :: enum { Procedure, Terminal_Color } +*/ +Options :: runtime.Logger_Options; +/* Options :: bit_set[Option]; +*/ + Full_Timestamp_Opts :: Options{ .Date, .Time @@ -37,13 +51,20 @@ Location_File_Opts :: Options{ .Long_File_Path }; -Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location); +Logger_Proc :: runtime.Logger_Proc; +/* +Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location); +*/ + +Logger :: runtime.Logger; +/* Logger :: struct { procedure: Logger_Proc, data: rawptr, options: Options, } +*/ Multi_Logger_Data :: struct { loggers : []Logger, diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index b0ccd3577..f938c7631 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -307,6 +307,14 @@ identity :: proc($T: typeid/[$N][N]$E) -> (m: T) { return m; } +trace :: proc(m: $T/[$N][N]$E) -> (tr: E) { + for i in 0.. (m: T) { for j in 0.. (roll, pitch, yaw: Float) } quaternion_look_at :: proc(eye, centre: Vector3, up: Vector3) -> Quaternion { - f := normalize(centre - eye); - s := normalize(cross(f, up)); - u := cross(s, f); + m := matrix3_look_at(eye, centre, up); + tr := trace(m); + + w, x, y, z: Float; + + switch { + case tr > 0: + S := 2 * math.sqrt(1 + tr); + w = 0.25 * S; + x = (m[2][1] - m[1][2]) / S; + y = (m[0][2] - m[2][0]) / S; + z = (m[1][0] - m[0][1]) / S; + case (m[0][0] > m[1][1]) && (m[0][0] > m[2][2]): + S := 2 * math.sqrt(1 + m[0][0] - m[1][1] - m[2][2]); + w = (m[2][1] - m[1][2]) / S; + x = 0.25 * S; + y = (m[0][1] + m[1][0]) / S; + z = (m[0][2] + m[2][0]) / S; + case m[1][1] > m[2][2]: + S := 2 * math.sqrt(1 + m[1][1] - m[0][0] - m[2][2]); + w = (m[0][2] - m[2][0]) / S; + x = (m[0][1] + m[1][0]) / S; + y = 0.25 * S; + z = (m[1][2] + m[2][1]) / S; + case: + S := 2 * math.sqrt(1 + m[2][2] - m[0][0] - m[1][1]); + w = (m[1][0] - m[0][1]) / S; + x = (m[0][2] - m[2][0]) / S; + y = (m[1][2] + m[2][1]) / S; + z = 0.25 * S; + } - w := math.sqrt(1 + s.x + u.y - f.z)*0.5; - iw4 := 0.25/w; - x := (+u.z + f.y)*iw4; - y := (-f.x - s.z)*iw4; - z := (+s.y - u.x)*iw4; q: Quaternion = quaternion(w, x, y, z); return normalize(q); } @@ -340,6 +363,16 @@ matrix2_inverse_transpose :: proc(m: Matrix2) -> Matrix2 { matrix2_determinant :: proc(m: Matrix2) -> Float { return m[0][0]*m[1][1] - m[1][0]*m[0][1]; } +matrix2_inverse :: proc(m: Matrix2) -> Matrix2 { + c: Matrix2; + d := m[0][0]*m[1][1] - m[1][0]*m[0][1]; + id := 1.0/d; + c[0][0] = +m[1][1] * id; + c[1][0] = -m[0][1] * id; + c[0][1] = -m[1][0] * id; + c[1][1] = +m[0][0] * id; + return c; +} matrix2_adjoint :: proc(m: Matrix2) -> Matrix2 { c: Matrix2; @@ -427,6 +460,41 @@ matrix3_scale :: proc(s: Vector3) -> Matrix3 { return m; } +matrix3_rotate :: proc(angle_radians: Float, v: Vector3) -> Matrix3 { + c := math.cos(angle_radians); + s := math.sin(angle_radians); + + a := normalize(v); + t := a * (1-c); + + rot: Matrix3 = ---; + + rot[0][0] = c + t[0]*a[0]; + rot[0][1] = 0 + t[0]*a[1] + s*a[2]; + rot[0][2] = 0 + t[0]*a[2] - s*a[1]; + + rot[1][0] = 0 + t[1]*a[0] - s*a[2]; + rot[1][1] = c + t[1]*a[1]; + rot[1][2] = 0 + t[1]*a[2] + s*a[0]; + + rot[2][0] = 0 + t[2]*a[0] + s*a[1]; + rot[2][1] = 0 + t[2]*a[1] - s*a[0]; + rot[2][2] = c + t[2]*a[2]; + + return rot; +} + +matrix3_look_at :: proc(eye, centre, up: Vector3) -> Matrix3 { + f := normalize(centre - eye); + s := normalize(cross(f, up)); + u := cross(s, f); + return Matrix3{ + {+s.x, +u.x, -f.x}, + {+s.y, +u.y, -f.y}, + {+s.z, +u.z, -f.z}, + }; +} + matrix4_from_quaternion :: proc(q: Quaternion) -> Matrix4 { m := identity(Matrix4); @@ -481,8 +549,9 @@ matrix4_minor :: proc(m: Matrix4, c, r: int) -> Float { } matrix4_cofactor :: proc(m: Matrix4, c, r: int) -> Float { - sign := (c + r) % 2 == 0 ? Float(1) : Float(-1); - minor := matrix4_minor(m, c, r); + sign, minor: Float; + sign = (c + r) % 2 == 0 ? 1 : -1; + minor = matrix4_minor(m, c, r); return sign * minor; } @@ -522,8 +591,6 @@ matrix4_inverse_transpose :: proc(m: Matrix4) -> Matrix4 { return inverse_transpose; } - -translate_matrix4 :: matrix4_translate; matrix4_translate :: proc(v: Vector3) -> Matrix4 { m := identity(Matrix4); m[3][0] = v[0]; @@ -533,8 +600,7 @@ matrix4_translate :: proc(v: Vector3) -> Matrix4 { } -rotate_matrix4 :: matrix4_rotate; -matrix4_rotate :: proc(v: Vector3, angle_radians: Float) -> Matrix4 { +matrix4_rotate :: proc(angle_radians: Float, v: Vector3) -> Matrix4 { c := math.cos(angle_radians); s := math.sin(angle_radians); diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index 38eda7a11..52ba19738 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -2,26 +2,33 @@ package mem import "core:runtime" -DEFAULT_ALIGNMENT :: 2*align_of(rawptr); - +// NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle. +Allocator_Mode :: runtime.Allocator_Mode; +/* Allocator_Mode :: enum byte { Alloc, Free, Free_All, Resize, } +*/ +Allocator_Proc :: runtime.Allocator_Proc; +/* Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, flags: u64 = 0, location := #caller_location) -> rawptr; - + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64 = 0, location := #caller_location) -> rawptr; +*/ +Allocator :: runtime.Allocator; +/* Allocator :: struct { procedure: Allocator_Proc, data: rawptr, } +*/ - +DEFAULT_ALIGNMENT :: 2*align_of(rawptr); alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { if size == 0 do return nil; diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 5d8260de0..362fb6182 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -99,6 +99,7 @@ Scratch_Allocator :: struct { prev_offset: int, backup_allocator: Allocator, leaked_allocations: [dynamic]rawptr, + default_to_default_allocator: bool, } scratch_allocator_init :: proc(scratch: ^Scratch_Allocator, data: []byte, backup_allocator := context.allocator) { @@ -128,13 +129,15 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, if scratch.data == nil { DEFAULT_SCRATCH_BACKING_SIZE :: 1<<22; - assert(context.allocator.procedure != scratch_allocator_proc && - context.allocator.data != allocator_data); + if !(context.allocator.procedure != scratch_allocator_proc && + context.allocator.data != allocator_data) { + panic("cyclic initialization of the scratch allocator with itself"); + } scratch_allocator_init(scratch, make([]byte, 1<<22)); } switch mode { - case Allocator_Mode.Alloc: + case .Alloc: switch { case scratch.curr_offset+size <= len(scratch.data): offset := align_forward_uintptr(uintptr(scratch.curr_offset), uintptr(alignment)); @@ -166,7 +169,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, return ptr; - case Allocator_Mode.Free: + case .Free: last_ptr := rawptr(&scratch.data[scratch.prev_offset]); if old_memory == last_ptr { full_size := scratch.curr_offset - scratch.prev_offset; @@ -176,7 +179,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, } // NOTE(bill): It's scratch memory, don't worry about freeing - case Allocator_Mode.Free_All: + case .Free_All: scratch.curr_offset = 0; scratch.prev_offset = 0; for ptr in scratch.leaked_allocations { @@ -184,7 +187,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, } clear(&scratch.leaked_allocations); - case Allocator_Mode.Resize: + case .Resize: last_ptr := rawptr(&scratch.data[scratch.prev_offset]); if old_memory == last_ptr && len(scratch.data)-scratch.prev_offset >= size { scratch.curr_offset = scratch.prev_offset+size; @@ -505,13 +508,13 @@ dynamic_pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode pool := (^Dynamic_Pool)(allocator_data); switch mode { - case Allocator_Mode.Alloc: + case .Alloc: return dynamic_pool_alloc(pool, size); - case Allocator_Mode.Free: + case .Free: panic("Allocator_Mode.Free is not supported for a pool"); - case Allocator_Mode.Free_All: + case .Free_All: dynamic_pool_free_all(pool); - case Allocator_Mode.Resize: + case .Resize: panic("Allocator_Mode.Resize is not supported for a pool"); if old_size >= size { return old_memory; diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 78be94560..2b11629d2 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -12,19 +12,7 @@ swap :: proc{swap16, swap32, swap64}; set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr { - if data == nil do return nil; - if len < 0 do return data; - foreign _ { - when size_of(rawptr) == 8 { - @(link_name="llvm.memset.p0i8.i64") - llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---; - } else { - @(link_name="llvm.memset.p0i8.i32") - llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---; - } - } - llvm_memset(data, byte(value), len, 1, false); - return data; + return runtime.memset(data, i32(value), len); } zero :: inline proc "contextless" (data: rawptr, len: int) -> rawptr { return set(data, 0, len); diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 932a1fbd0..845f1cc22 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -4,8 +4,6 @@ package runtime import "core:os" -import "core:mem" -import "core:log" import "intrinsics" // Naming Conventions: @@ -234,11 +232,58 @@ Source_Code_Location :: struct { Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location); + +// Allocation Stuff +Allocator_Mode :: enum byte { + Alloc, + Free, + Free_All, + Resize, +} + +Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64 = 0, location: Source_Code_Location = #caller_location) -> rawptr; +Allocator :: struct { + procedure: Allocator_Proc, + data: rawptr, +} + +// Logging stuff + +Logger_Level :: enum { + Debug, + Info, + Warning, + Error, + Fatal, +} + +Logger_Option :: enum { + Level, + Date, + Time, + Short_File_Path, + Long_File_Path, + Line, + Procedure, + Terminal_Color +} + +Logger_Options :: bit_set[Logger_Option]; +Logger_Proc :: #type proc(data: rawptr, level: Logger_Level, text: string, options: Logger_Options, location := #caller_location); + +Logger :: struct { + procedure: Logger_Proc, + data: rawptr, + options: Logger_Options, +} + Context :: struct { - allocator: mem.Allocator, - temp_allocator: mem.Allocator, + allocator: Allocator, + temp_allocator: Allocator, assertion_failure_proc: Assertion_Failure_Proc, - logger: log.Logger, + logger: Logger, stdin: os.Handle, stdout: os.Handle, @@ -253,13 +298,16 @@ Context :: struct { derived: any, // May be used for derived data types } -@thread_local global_scratch_allocator_data: mem.Scratch_Allocator; -global_scratch_allocator_proc :: mem.scratch_allocator_proc; -global_scratch_allocator_init :: mem.scratch_allocator_init; -global_scratch_allocator_destroy :: mem.scratch_allocator_destroy; +@thread_local global_default_temp_allocator_data: Default_Temp_Allocator; + +Raw_String :: struct { + data: ^byte, + len: int, +} + Raw_Slice :: struct { data: rawptr, len: int, @@ -269,7 +317,7 @@ Raw_Dynamic_Array :: struct { data: rawptr, len: int, cap: int, - allocator: mem.Allocator, + allocator: Allocator, } Raw_Map :: struct { @@ -381,6 +429,13 @@ foreign { +default_logger_proc :: proc(data: rawptr, level: Logger_Level, text: string, options: Logger_Options, location := #caller_location) { + // Do nothing +} + +default_logger :: proc() -> Logger { + return Logger{default_logger_proc, nil, nil}; +} __init_context_from_ptr :: proc "contextless" (c: ^Context, other: ^Context) { @@ -392,16 +447,17 @@ __init_context_from_ptr :: proc "contextless" (c: ^Context, other: ^Context) { __init_context :: proc "contextless" (c: ^Context) { if c == nil do return; - c.allocator.procedure = os.heap_allocator_proc; + // NOTE(bill): Do not initialize these procedures with a call as they are not defined with the "contexless" calling convention + c.allocator.procedure = default_allocator_proc; c.allocator.data = nil; - c.temp_allocator.procedure = global_scratch_allocator_proc; - c.temp_allocator.data = &global_scratch_allocator_data; + c.temp_allocator.procedure = default_temp_allocator_proc; + c.temp_allocator.data = &global_default_temp_allocator_data; c.thread_id = os.current_thread_id(); // NOTE(bill): This is "contextless" so it is okay to call c.assertion_failure_proc = default_assertion_failure_proc; - c.logger.procedure = log.nil_logger_proc; + c.logger.procedure = default_logger_proc; c.logger.data = nil; c.stdin = os.stdin; @@ -411,7 +467,7 @@ __init_context :: proc "contextless" (c: ^Context) { @builtin init_global_temporary_allocator :: proc(data: []byte, backup_allocator := context.allocator) { - global_scratch_allocator_init(&global_scratch_allocator_data, data, backup_allocator); + default_temp_allocator_init(&global_default_temp_allocator_data, data, backup_allocator); } default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) { @@ -491,35 +547,112 @@ resize :: proc{resize_dynamic_array}; @builtin -new :: proc{mem.new}; +free :: proc{mem_free}; @builtin -new_clone :: proc{mem.new_clone}; +free_all :: proc{mem_free_all}; + + @builtin -free :: proc{mem.free}; - +delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) { + mem_free((transmute(Raw_String)str).data, allocator, loc); +} @builtin -free_all :: proc{mem.free_all}; +delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) { + mem_free((^byte)(str), allocator, loc); +} +@builtin +delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) { + mem_free((transmute(Raw_Dynamic_Array)array).data, array.allocator, loc); +} +@builtin +delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) { + mem_free((transmute(Raw_Slice)array).data, allocator, loc); +} +@builtin +delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) { + raw := transmute(Raw_Map)m; + delete_slice(raw.hashes); + mem_free(raw.entries.data, raw.entries.allocator, loc); +} + @builtin delete :: proc{ - mem.delete_string, - mem.delete_cstring, - mem.delete_dynamic_array, - mem.delete_slice, - mem.delete_map, + delete_string, + delete_cstring, + delete_dynamic_array, + delete_slice, + delete_map, }; + +@builtin +new :: inline 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 do ptr^ = T{}; + return ptr; +} + +@builtin +new_clone :: inline 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 do ptr^ = data; + return ptr; +} + +make_aligned :: proc($T: typeid/[]$E, auto_cast len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> T { + make_slice_error_loc(loc, len); + data := mem_alloc(size_of(E)*len, alignment, allocator, loc); + s := Raw_Slice{data, len}; + return transmute(T)s; +} + +@builtin +make_slice :: inline proc($T: typeid/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T { + 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 { + return make_dynamic_array_len_cap(T, 0, 16, allocator, loc); +} + +@builtin +make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T { + 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_error_loc(loc, len, cap); + data := mem_alloc(size_of(E)*cap, align_of(E), allocator, loc); + s := Raw_Dynamic_Array{data, len, cap, allocator}; + return transmute(T)s; +} + +@builtin +make_map :: proc($T: typeid/map[$K]$E, auto_cast cap: int = 16, allocator := context.allocator, loc := #caller_location) -> T { + make_map_expr_error_loc(loc, cap); + context.allocator = allocator; + + m: T; + reserve_map(&m, cap); + return m; +} + @builtin make :: proc{ - mem.make_slice, - mem.make_dynamic_array, - mem.make_dynamic_array_len, - mem.make_dynamic_array_len_cap, - mem.make_map, + make_slice, + make_dynamic_array, + make_dynamic_array_len, + make_dynamic_array_len_cap, + make_map, }; + + @builtin clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) { if m == nil do return; @@ -559,7 +692,7 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) { data := (^E)(a.data); assert(data != nil); val := arg; - mem_copy(mem.ptr_offset(data, a.len), &val, size_of(E)); + mem_copy(ptr_offset(data, a.len), &val, size_of(E)); a.len += arg_len; } } @@ -580,7 +713,7 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) a := (^Raw_Dynamic_Array)(array); data := (^E)(a.data); assert(data != nil); - mem_copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len); + mem_copy(ptr_offset(data, a.len), &args[0], size_of(E) * arg_len); a.len += arg_len; } } @@ -625,20 +758,20 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo type := si.types[i].variant.(Type_Info_Pointer).elem; max_align = max(max_align, type.align); - old_size = mem.align_forward_int(old_size, type.align); - new_size = mem.align_forward_int(new_size, type.align); + old_size = align_forward_int(old_size, type.align); + new_size = align_forward_int(new_size, type.align); old_size += type.size * old_cap; new_size += type.size * capacity; } - old_size = mem.align_forward_int(old_size, max_align); - new_size = mem.align_forward_int(new_size, max_align); + old_size = align_forward_int(old_size, max_align); + new_size = align_forward_int(new_size, max_align); old_data := (^rawptr)(array)^; new_data := array.allocator.procedure( - array.allocator.data, mem.Allocator_Mode.Alloc, new_size, max_align, + array.allocator.data, .Alloc, new_size, max_align, nil, old_size, 0, loc, ); if new_data == nil do return false; @@ -652,8 +785,8 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo type := si.types[i].variant.(Type_Info_Pointer).elem; max_align = max(max_align, type.align); - old_offset = mem.align_forward_int(old_offset, type.align); - new_offset = mem.align_forward_int(new_offset, type.align); + old_offset = align_forward_int(old_offset, type.align); + new_offset = align_forward_int(new_offset, type.align); new_data_elem := rawptr(uintptr(new_data) + uintptr(new_offset)); old_data_elem := rawptr(uintptr(old_data) + uintptr(old_offset)); @@ -667,7 +800,7 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo } array.allocator.procedure( - array.allocator.data, mem.Allocator_Mode.Free, 0, max_align, + array.allocator.data, .Free, 0, max_align, old_data, old_size, 0, loc, ); @@ -711,8 +844,8 @@ append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_locat type := si.types[i].variant.(Type_Info_Pointer).elem; max_align = max(max_align, type.align); - soa_offset = mem.align_forward_int(soa_offset, type.align); - item_offset = mem.align_forward_int(item_offset, type.align); + soa_offset = align_forward_int(soa_offset, type.align); + item_offset = align_forward_int(item_offset, type.align); dst := rawptr(uintptr(data) + uintptr(soa_offset) + uintptr(type.size * len_ptr^)); src := rawptr(uintptr(arg_ptr) + uintptr(item_offset)); @@ -765,8 +898,8 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l type := si.types[i].variant.(Type_Info_Pointer).elem; max_align = max(max_align, type.align); - soa_offset = mem.align_forward_int(soa_offset, type.align); - item_offset = mem.align_forward_int(item_offset, type.align); + soa_offset = align_forward_int(soa_offset, type.align); + item_offset = align_forward_int(item_offset, type.align); dst := uintptr(data) + uintptr(soa_offset) + uintptr(type.size * len_ptr^); src := uintptr(args_ptr) + uintptr(item_offset); @@ -818,7 +951,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal allocator := a.allocator; new_data := allocator.procedure( - allocator.data, mem.Allocator_Mode.Resize, new_size, align_of(E), + allocator.data, .Resize, new_size, align_of(E), a.data, old_size, 0, loc, ); if new_data == nil do return false; @@ -848,7 +981,7 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller allocator := a.allocator; new_data := allocator.procedure( - allocator.data, mem.Allocator_Mode.Resize, new_size, align_of(E), + allocator.data, .Resize, new_size, align_of(E), a.data, old_size, 0, loc, ); if new_data == nil do return false; @@ -998,7 +1131,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: new_size := cap * elem_size; allocator := array.allocator; - new_data := allocator.procedure(allocator.data, mem.Allocator_Mode.Resize, new_size, elem_align, array.data, old_size, 0, loc); + new_data := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, 0, loc); if new_data == nil do return false; array.data = new_data; @@ -1052,7 +1185,7 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in assert(array.data != nil); data := uintptr(array.data) + uintptr(elem_size*array.len); - mem.zero(rawptr(data), elem_size); + mem_zero(rawptr(data), elem_size); array.len += 1; return array.len; } @@ -1136,7 +1269,7 @@ source_code_location_hash :: proc(s: Source_Code_Location) -> u64 { -__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool { +__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool { array := (^Raw_Slice)(array_); if new_count < array.len do return true; @@ -1146,7 +1279,7 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocato old_size := array.len*size_of(T); new_size := new_count*size_of(T); - new_data := mem.resize(array.data, old_size, new_size, align_of(T), allocator, loc); + new_data := mem_resize(array.data, old_size, new_size, align_of(T), allocator, loc); if new_data == nil do return false; array.data = new_data; array.len = new_count; diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index dd86fb55e..60359fd6c 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -2,6 +2,57 @@ package runtime import "core:os" +ptr_offset :: inline proc "contextless" (ptr: $P/^$T, n: int) -> P { + new := int(uintptr(ptr)) + size_of(T)*n; + return P(uintptr(new)); +} + +is_power_of_two_int :: inline proc(x: int) -> bool { + if x <= 0 do return false; + return (x & (x-1)) == 0; +} + +align_forward_int :: inline proc(ptr, align: int) -> int { + assert(is_power_of_two_int(align)); + + p := ptr; + modulo := p & (align-1); + if modulo != 0 do p += align - modulo; + return p; +} + +is_power_of_two_uintptr :: inline proc(x: uintptr) -> bool { + if x <= 0 do return false; + return (x & (x-1)) == 0; +} + +align_forward_uintptr :: inline proc(ptr, align: uintptr) -> uintptr { + assert(is_power_of_two_uintptr(align)); + + p := ptr; + modulo := p & (align-1); + if modulo != 0 do p += align - modulo; + return p; +} + +mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr { + if data == nil do return nil; + if len < 0 do return data; + when !#defined(memset) { + foreign _ { + when size_of(rawptr) == 8 { + @(link_name="llvm.memset.p0i8.i64") + memset :: proc(dst: rawptr, val: byte, len: int, align: i32 = 1, is_volatile: bool = false) ---; + } else { + @(link_name="llvm.memset.p0i8.i32") + memset :: proc(dst: rawptr, val: byte, len: int, align: i32 = 1, is_volatile: bool = false) ---; + } + } + } + memset(data, 0, len); + return data; +} + mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { if src == nil do return dst; // NOTE(bill): This _must_ be implemented like C's memmove @@ -34,6 +85,47 @@ mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> r return dst; } +DEFAULT_ALIGNMENT :: 2*align_of(rawptr); + +mem_alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { + if size == 0 do return nil; + if allocator.procedure == nil do return nil; + return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, 0, loc); +} + +mem_free :: inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) { + if ptr == nil do return; + if allocator.procedure == nil do return; + allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, 0, loc); +} + +mem_free_all :: inline proc(allocator := context.allocator, loc := #caller_location) { + if allocator.procedure != nil { + allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, 0, loc); + } +} + +mem_resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { + switch { + case allocator.procedure == nil: + return nil; + case new_size == 0: + allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, 0, loc); + return nil; + case ptr == nil: + return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, 0, loc); + } + return allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, 0, loc); +} + + + + + + + + + print_u64 :: proc(fd: os.Handle, x: u64) { digits := "0123456789"; @@ -380,12 +472,6 @@ memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_ return 0; } -@private -Raw_String :: struct { - data: ^byte, - len: int, -}; - string_eq :: proc "contextless" (a, b: string) -> bool { x := transmute(Raw_String)a; y := transmute(Raw_String)b; diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 79ebe48d6..fb8915057 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -37,8 +37,8 @@ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^T t.procedure(t); if !t.use_init_context { - if context.temp_allocator.data == &runtime.global_scratch_allocator_data { - runtime.global_scratch_allocator_destroy(auto_cast context.temp_allocator.data); + if context.temp_allocator.data == &runtime.global_default_temp_allocator_data { + runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data); } } diff --git a/src/checker.cpp b/src/checker.cpp index bc98837d1..9db6b94e9 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1660,13 +1660,21 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { ptr_set_init(&c->info.minimum_dependency_type_info_set, heap_allocator()); String required_runtime_entities[] = { + str_lit("Allocator"), + str_lit("Logger"), + str_lit("mem_zero"), + str_lit("__init_context"), str_lit("default_assertion_failure_proc"), str_lit("args__"), str_lit("type_table"), str_lit("__type_info_of"), - str_lit("global_scratch_allocator"), + str_lit("global_default_temp_allocator_data"), + str_lit("default_temp_allocator"), + str_lit("default_temp_allocator_init"), + str_lit("default_temp_allocator_destroy"), + str_lit("default_temp_allocator_proc"), str_lit("Type_Info"), str_lit("Source_Code_Location"), @@ -1683,6 +1691,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("umodti3"), str_lit("udivti3"), + str_lit("memset"), + str_lit("memory_compare"), str_lit("memory_compare_zero"), }; @@ -1695,7 +1705,6 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { // NOTE(bill): Only if these exist str_lit("memcpy"), str_lit("memmove"), - str_lit("memset"), str_lit("_tls_index"), str_lit("_fltused"), }; @@ -1704,15 +1713,6 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { } } - AstPackage *mem = get_core_package(&c->info, str_lit("mem")); - String required_mem_entities[] = { - str_lit("zero"), - str_lit("Allocator"), - }; - for (isize i = 0; i < gb_count_of(required_mem_entities); i++) { - add_dependency_to_set(c, scope_lookup(mem->scope, required_mem_entities[i])); - } - AstPackage *os = get_core_package(&c->info, str_lit("os")); String required_os_entities[] = { str_lit("heap_allocator"), @@ -1863,6 +1863,7 @@ Array generate_entity_dependency_graph(CheckerInfo *info) { } +void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d); Entity *find_core_entity(Checker *c, String name) { @@ -1882,6 +1883,10 @@ Type *find_core_type(Checker *c, String name) { , LIT(name)); // NOTE(bill): This will exit the program as it's cannot continue without it! } + if (e->type == nullptr) { + check_single_global_entity(c, e, e->decl_info); + } + GB_ASSERT(e->type != nullptr); return e->type; } @@ -2031,7 +2036,7 @@ void init_mem_allocator(Checker *c) { if (t_allocator != nullptr) { return; } - AstPackage *pkg = get_core_package(&c->info, str_lit("mem")); + AstPackage *pkg = get_core_package(&c->info, str_lit("runtime")); String name = str_lit("Allocator"); Entity *e = scope_lookup_current(pkg->scope, name); @@ -2049,6 +2054,7 @@ void init_core_context(Checker *c) { return; } t_context = find_core_type(c, str_lit("Context")); + GB_ASSERT(t_context != nullptr); t_context_ptr = alloc_type_pointer(t_context); } @@ -2905,46 +2911,56 @@ void check_collect_entities(CheckerContext *c, Array const &nodes) { } +void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d) { + GB_ASSERT(e != nullptr); + GB_ASSERT(d != nullptr); + + if (d->scope != e->scope) { + return; + } + if (e->state == EntityState_Resolved) { + return; + } + + CheckerContext ctx = c->init_ctx; + + GB_ASSERT(d->scope->flags&ScopeFlag_File); + AstFile *file = d->scope->file; + add_curr_ast_file(&ctx, file); + AstPackage *pkg = file->pkg; + + GB_ASSERT(ctx.pkg != nullptr); + GB_ASSERT(e->pkg != nullptr); + + if (!e->pkg->used) { + return; + } + + + if (pkg->kind == Package_Init) { + if (e->kind != Entity_Procedure && e->token.string == "main") { + error(e->token, "'main' is reserved as the entry point procedure in the initial scope"); + return; + } + } else if (pkg->kind == Package_Runtime) { + if (e->token.string == "main") { + error(e->token, "'main' is reserved as the entry point procedure in the initial scope"); + return; + } + } + + ctx.decl = d; + ctx.scope = d->scope; + check_entity_decl(&ctx, e, d, nullptr); +} + void check_all_global_entities(Checker *c) { Scope *prev_file = nullptr; for_array(i, c->info.entities) { Entity *e = c->info.entities[i]; DeclInfo *d = e->decl_info; - - if (d->scope != e->scope) { - continue; - } - - CheckerContext ctx = c->init_ctx; - - GB_ASSERT(d->scope->flags&ScopeFlag_File); - AstFile *file = d->scope->file; - add_curr_ast_file(&ctx, file); - AstPackage *pkg = file->pkg; - - GB_ASSERT(ctx.pkg != nullptr); - GB_ASSERT(e->pkg != nullptr); - - if (!e->pkg->used) { - continue; - } - - if (pkg->kind == Package_Init) { - if (e->kind != Entity_Procedure && e->token.string == "main") { - error(e->token, "'main' is reserved as the entry point procedure in the initial scope"); - continue; - } - } else if (pkg->kind == Package_Runtime) { - if (e->token.string == "main") { - error(e->token, "'main' is reserved as the entry point procedure in the initial scope"); - continue; - } - } - - ctx.decl = d; - ctx.scope = d->scope; - check_entity_decl(&ctx, e, d, nullptr); + check_single_global_entity(c, e, d); } } diff --git a/src/ir.cpp b/src/ir.cpp index dd9ba73cc..b0d43d7f4 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3006,11 +3006,13 @@ void ir_emit_zero_init(irProcedure *p, irValue *address, Ast *expr) { auto args = array_make(a, 2); args[0] = ir_emit_conv(p, address, t_rawptr); args[1] = ir_const_int(type_size_of(t)); - AstPackage *pkg = get_core_package(p->module->info, str_lit("mem")); - if (p->entity != nullptr && p->entity->token.string != "zero" && p->entity->pkg != pkg) { - ir_emit_comment(p, str_lit("ZeroInit")); - irValue *v = ir_emit_package_call(p, "mem", "zero", args, expr); - return; + AstPackage *pkg_runtime = get_core_package(p->module->info, str_lit("runtime")); + if (p->entity != nullptr) { + if (p->entity->pkg != pkg_runtime && p->entity->token.string != "mem_zero") { + ir_emit_comment(p, str_lit("ZeroInit")); + irValue *v = ir_emit_package_call(p, "runtime", "mem_zero", args, expr); + return; + } } } ir_emit(p, ir_instr_zero_init(p, address)); @@ -3254,7 +3256,7 @@ irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char AstPackage *p = get_core_package(proc->module->info, package_name); Entity *e = scope_lookup_current(p->scope, name); irValue **found = map_get(&proc->module->values, hash_entity(e)); - GB_ASSERT_MSG(found != nullptr, "%.*s", LIT(name)); + GB_ASSERT_MSG(found != nullptr, "%s.%.*s", package_name_, LIT(name)); irValue *gp = *found; irValue *call = ir_emit_call(proc, gp, args, inlining); return call;