Browse Source

Move definition of mem.Allocator and log.Logger to `package runtime`, to reduce import cycle magic

gingerBill 5 years ago
parent
commit
ab52f8d795

+ 21 - 0
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 :: 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,

+ 8 - 0
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..<N {
+		tr += m[i][i];
+	}
+	return;
+}
+
+
 transpose :: proc(a: $T/[$N][$M]$E) -> (m: T) {
 	for j in 0..<M {
 		for i in 0..<N {

+ 80 - 14
core/math/linalg/specific.odin

@@ -202,15 +202,38 @@ euler_angles_from_quaternion :: proc(q: Quaternion) -> (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);
 

+ 13 - 6
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;

+ 13 - 10
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;

+ 1 - 13
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);

+ 183 - 50
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};
 
+
+@builtin
+delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) {
+	mem_free((transmute(Raw_String)str).data, allocator, loc);
+}
+@builtin
+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
-free_all :: proc{mem.free_all};
+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;

+ 92 - 6
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;

+ 2 - 2
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);
 			}
 		}
 

+ 59 - 43
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<EntityGraphNode *> 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<Ast *> const &nodes) {
 }
 
 
-void check_all_global_entities(Checker *c) {
-	Scope *prev_file = nullptr;
+void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d) {
+	GB_ASSERT(e != nullptr);
+	GB_ASSERT(d != nullptr);
 
-	for_array(i, c->info.entities) {
-		Entity *e = c->info.entities[i];
-		DeclInfo *d = e->decl_info;
+	if (d->scope != e->scope) {
+		return;
+	}
+	if (e->state == EntityState_Resolved)  {
+		return;
+	}
 
-		if (d->scope != e->scope) {
-			continue;
-		}
+	CheckerContext ctx = c->init_ctx;
 
-		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(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);
 
-		GB_ASSERT(ctx.pkg != nullptr);
-		GB_ASSERT(e->pkg != nullptr);
+	if (!e->pkg->used) {
+		return;
+	}
 
-		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;
-			}
+	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;
 
-		ctx.decl = d;
-		ctx.scope = d->scope;
-		check_entity_decl(&ctx, e, d, nullptr);
+	for_array(i, c->info.entities) {
+		Entity *e = c->info.entities[i];
+		DeclInfo *d = e->decl_info;
+		check_single_global_entity(c, e, d);
 	}
 }
 

+ 8 - 6
src/ir.cpp

@@ -3006,11 +3006,13 @@ void ir_emit_zero_init(irProcedure *p, irValue *address, Ast *expr) {
 		auto args = array_make<irValue *>(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;