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

This commit is contained in:
gingerBill
2019-12-31 12:15:19 +00:00
parent 7e271310ff
commit ab52f8d795
11 changed files with 484 additions and 154 deletions

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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_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);
}
}

View File

@@ -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;