mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Move definition of mem.Allocator and log.Logger to package runtime, to reduce import cycle magic
This commit is contained in:
+22
-1
@@ -1,7 +1,13 @@
|
|||||||
package log
|
package log
|
||||||
|
|
||||||
|
import "core:runtime"
|
||||||
import "core:fmt"
|
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 {
|
Level :: enum {
|
||||||
Debug,
|
Debug,
|
||||||
Info,
|
Info,
|
||||||
@@ -9,7 +15,10 @@ Level :: enum {
|
|||||||
Error,
|
Error,
|
||||||
Fatal,
|
Fatal,
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Option :: runtime.Logger_Option;
|
||||||
|
/*
|
||||||
Option :: enum {
|
Option :: enum {
|
||||||
Level,
|
Level,
|
||||||
Date,
|
Date,
|
||||||
@@ -20,8 +29,13 @@ Option :: enum {
|
|||||||
Procedure,
|
Procedure,
|
||||||
Terminal_Color
|
Terminal_Color
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Options :: runtime.Logger_Options;
|
||||||
|
/*
|
||||||
Options :: bit_set[Option];
|
Options :: bit_set[Option];
|
||||||
|
*/
|
||||||
|
|
||||||
Full_Timestamp_Opts :: Options{
|
Full_Timestamp_Opts :: Options{
|
||||||
.Date,
|
.Date,
|
||||||
.Time
|
.Time
|
||||||
@@ -37,13 +51,20 @@ Location_File_Opts :: Options{
|
|||||||
.Long_File_Path
|
.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 {
|
Logger :: struct {
|
||||||
procedure: Logger_Proc,
|
procedure: Logger_Proc,
|
||||||
data: rawptr,
|
data: rawptr,
|
||||||
options: Options,
|
options: Options,
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
Multi_Logger_Data :: struct {
|
Multi_Logger_Data :: struct {
|
||||||
loggers : []Logger,
|
loggers : []Logger,
|
||||||
|
|||||||
@@ -307,6 +307,14 @@ identity :: proc($T: typeid/[$N][N]$E) -> (m: T) {
|
|||||||
return m;
|
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) {
|
transpose :: proc(a: $T/[$N][$M]$E) -> (m: T) {
|
||||||
for j in 0..<M {
|
for j in 0..<M {
|
||||||
for i in 0..<N {
|
for i in 0..<N {
|
||||||
|
|||||||
@@ -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 {
|
quaternion_look_at :: proc(eye, centre: Vector3, up: Vector3) -> Quaternion {
|
||||||
f := normalize(centre - eye);
|
m := matrix3_look_at(eye, centre, up);
|
||||||
s := normalize(cross(f, up));
|
tr := trace(m);
|
||||||
u := cross(s, f);
|
|
||||||
|
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);
|
q: Quaternion = quaternion(w, x, y, z);
|
||||||
return normalize(q);
|
return normalize(q);
|
||||||
}
|
}
|
||||||
@@ -340,6 +363,16 @@ matrix2_inverse_transpose :: proc(m: Matrix2) -> Matrix2 {
|
|||||||
matrix2_determinant :: proc(m: Matrix2) -> Float {
|
matrix2_determinant :: proc(m: Matrix2) -> Float {
|
||||||
return m[0][0]*m[1][1] - m[1][0]*m[0][1];
|
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 {
|
matrix2_adjoint :: proc(m: Matrix2) -> Matrix2 {
|
||||||
c: Matrix2;
|
c: Matrix2;
|
||||||
@@ -427,6 +460,41 @@ matrix3_scale :: proc(s: Vector3) -> Matrix3 {
|
|||||||
return m;
|
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 {
|
matrix4_from_quaternion :: proc(q: Quaternion) -> Matrix4 {
|
||||||
m := identity(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 {
|
matrix4_cofactor :: proc(m: Matrix4, c, r: int) -> Float {
|
||||||
sign := (c + r) % 2 == 0 ? Float(1) : Float(-1);
|
sign, minor: Float;
|
||||||
minor := matrix4_minor(m, c, r);
|
sign = (c + r) % 2 == 0 ? 1 : -1;
|
||||||
|
minor = matrix4_minor(m, c, r);
|
||||||
return sign * minor;
|
return sign * minor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,8 +591,6 @@ matrix4_inverse_transpose :: proc(m: Matrix4) -> Matrix4 {
|
|||||||
return inverse_transpose;
|
return inverse_transpose;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
translate_matrix4 :: matrix4_translate;
|
|
||||||
matrix4_translate :: proc(v: Vector3) -> Matrix4 {
|
matrix4_translate :: proc(v: Vector3) -> Matrix4 {
|
||||||
m := identity(Matrix4);
|
m := identity(Matrix4);
|
||||||
m[3][0] = v[0];
|
m[3][0] = v[0];
|
||||||
@@ -533,8 +600,7 @@ matrix4_translate :: proc(v: Vector3) -> Matrix4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rotate_matrix4 :: matrix4_rotate;
|
matrix4_rotate :: proc(angle_radians: Float, v: Vector3) -> Matrix4 {
|
||||||
matrix4_rotate :: proc(v: Vector3, angle_radians: Float) -> Matrix4 {
|
|
||||||
c := math.cos(angle_radians);
|
c := math.cos(angle_radians);
|
||||||
s := math.sin(angle_radians);
|
s := math.sin(angle_radians);
|
||||||
|
|
||||||
|
|||||||
+13
-6
@@ -2,26 +2,33 @@ package mem
|
|||||||
|
|
||||||
import "core:runtime"
|
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 {
|
Allocator_Mode :: enum byte {
|
||||||
Alloc,
|
Alloc,
|
||||||
Free,
|
Free,
|
||||||
Free_All,
|
Free_All,
|
||||||
Resize,
|
Resize,
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Allocator_Proc :: runtime.Allocator_Proc;
|
||||||
|
/*
|
||||||
Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
|
Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64 = 0, location := #caller_location) -> rawptr;
|
old_memory: rawptr, old_size: int, flags: u64 = 0, location := #caller_location) -> rawptr;
|
||||||
|
*/
|
||||||
|
|
||||||
|
Allocator :: runtime.Allocator;
|
||||||
|
/*
|
||||||
Allocator :: struct {
|
Allocator :: struct {
|
||||||
procedure: Allocator_Proc,
|
procedure: Allocator_Proc,
|
||||||
data: rawptr,
|
data: rawptr,
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEFAULT_ALIGNMENT :: 2*align_of(rawptr);
|
||||||
|
|
||||||
alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
|
alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
|
||||||
if size == 0 do return nil;
|
if size == 0 do return nil;
|
||||||
|
|||||||
+13
-10
@@ -99,6 +99,7 @@ Scratch_Allocator :: struct {
|
|||||||
prev_offset: int,
|
prev_offset: int,
|
||||||
backup_allocator: Allocator,
|
backup_allocator: Allocator,
|
||||||
leaked_allocations: [dynamic]rawptr,
|
leaked_allocations: [dynamic]rawptr,
|
||||||
|
default_to_default_allocator: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch_allocator_init :: proc(scratch: ^Scratch_Allocator, data: []byte, backup_allocator := context.allocator) {
|
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 {
|
if scratch.data == nil {
|
||||||
DEFAULT_SCRATCH_BACKING_SIZE :: 1<<22;
|
DEFAULT_SCRATCH_BACKING_SIZE :: 1<<22;
|
||||||
assert(context.allocator.procedure != scratch_allocator_proc &&
|
if !(context.allocator.procedure != scratch_allocator_proc &&
|
||||||
context.allocator.data != allocator_data);
|
context.allocator.data != allocator_data) {
|
||||||
|
panic("cyclic initialization of the scratch allocator with itself");
|
||||||
|
}
|
||||||
scratch_allocator_init(scratch, make([]byte, 1<<22));
|
scratch_allocator_init(scratch, make([]byte, 1<<22));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case Allocator_Mode.Alloc:
|
case .Alloc:
|
||||||
switch {
|
switch {
|
||||||
case scratch.curr_offset+size <= len(scratch.data):
|
case scratch.curr_offset+size <= len(scratch.data):
|
||||||
offset := align_forward_uintptr(uintptr(scratch.curr_offset), uintptr(alignment));
|
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;
|
return ptr;
|
||||||
|
|
||||||
case Allocator_Mode.Free:
|
case .Free:
|
||||||
last_ptr := rawptr(&scratch.data[scratch.prev_offset]);
|
last_ptr := rawptr(&scratch.data[scratch.prev_offset]);
|
||||||
if old_memory == last_ptr {
|
if old_memory == last_ptr {
|
||||||
full_size := scratch.curr_offset - scratch.prev_offset;
|
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
|
// NOTE(bill): It's scratch memory, don't worry about freeing
|
||||||
|
|
||||||
case Allocator_Mode.Free_All:
|
case .Free_All:
|
||||||
scratch.curr_offset = 0;
|
scratch.curr_offset = 0;
|
||||||
scratch.prev_offset = 0;
|
scratch.prev_offset = 0;
|
||||||
for ptr in scratch.leaked_allocations {
|
for ptr in scratch.leaked_allocations {
|
||||||
@@ -184,7 +187,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
}
|
}
|
||||||
clear(&scratch.leaked_allocations);
|
clear(&scratch.leaked_allocations);
|
||||||
|
|
||||||
case Allocator_Mode.Resize:
|
case .Resize:
|
||||||
last_ptr := rawptr(&scratch.data[scratch.prev_offset]);
|
last_ptr := rawptr(&scratch.data[scratch.prev_offset]);
|
||||||
if old_memory == last_ptr && len(scratch.data)-scratch.prev_offset >= size {
|
if old_memory == last_ptr && len(scratch.data)-scratch.prev_offset >= size {
|
||||||
scratch.curr_offset = 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);
|
pool := (^Dynamic_Pool)(allocator_data);
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case Allocator_Mode.Alloc:
|
case .Alloc:
|
||||||
return dynamic_pool_alloc(pool, size);
|
return dynamic_pool_alloc(pool, size);
|
||||||
case Allocator_Mode.Free:
|
case .Free:
|
||||||
panic("Allocator_Mode.Free is not supported for a pool");
|
panic("Allocator_Mode.Free is not supported for a pool");
|
||||||
case Allocator_Mode.Free_All:
|
case .Free_All:
|
||||||
dynamic_pool_free_all(pool);
|
dynamic_pool_free_all(pool);
|
||||||
case Allocator_Mode.Resize:
|
case .Resize:
|
||||||
panic("Allocator_Mode.Resize is not supported for a pool");
|
panic("Allocator_Mode.Resize is not supported for a pool");
|
||||||
if old_size >= size {
|
if old_size >= size {
|
||||||
return old_memory;
|
return old_memory;
|
||||||
|
|||||||
+1
-13
@@ -12,19 +12,7 @@ swap :: proc{swap16, swap32, swap64};
|
|||||||
|
|
||||||
|
|
||||||
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
|
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
|
||||||
if data == nil do return nil;
|
return runtime.memset(data, i32(value), len);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
zero :: inline proc "contextless" (data: rawptr, len: int) -> rawptr {
|
zero :: inline proc "contextless" (data: rawptr, len: int) -> rawptr {
|
||||||
return set(data, 0, len);
|
return set(data, 0, len);
|
||||||
|
|||||||
+183
-50
@@ -4,8 +4,6 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import "core:os"
|
import "core:os"
|
||||||
import "core:mem"
|
|
||||||
import "core:log"
|
|
||||||
import "intrinsics"
|
import "intrinsics"
|
||||||
|
|
||||||
// Naming Conventions:
|
// Naming Conventions:
|
||||||
@@ -234,11 +232,58 @@ Source_Code_Location :: struct {
|
|||||||
|
|
||||||
Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location);
|
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 {
|
Context :: struct {
|
||||||
allocator: mem.Allocator,
|
allocator: Allocator,
|
||||||
temp_allocator: mem.Allocator,
|
temp_allocator: Allocator,
|
||||||
assertion_failure_proc: Assertion_Failure_Proc,
|
assertion_failure_proc: Assertion_Failure_Proc,
|
||||||
logger: log.Logger,
|
logger: Logger,
|
||||||
|
|
||||||
stdin: os.Handle,
|
stdin: os.Handle,
|
||||||
stdout: os.Handle,
|
stdout: os.Handle,
|
||||||
@@ -253,13 +298,16 @@ Context :: struct {
|
|||||||
derived: any, // May be used for derived data types
|
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 {
|
Raw_Slice :: struct {
|
||||||
data: rawptr,
|
data: rawptr,
|
||||||
len: int,
|
len: int,
|
||||||
@@ -269,7 +317,7 @@ Raw_Dynamic_Array :: struct {
|
|||||||
data: rawptr,
|
data: rawptr,
|
||||||
len: int,
|
len: int,
|
||||||
cap: int,
|
cap: int,
|
||||||
allocator: mem.Allocator,
|
allocator: Allocator,
|
||||||
}
|
}
|
||||||
|
|
||||||
Raw_Map :: struct {
|
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) {
|
__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) {
|
__init_context :: proc "contextless" (c: ^Context) {
|
||||||
if c == nil do return;
|
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.allocator.data = nil;
|
||||||
|
|
||||||
c.temp_allocator.procedure = global_scratch_allocator_proc;
|
c.temp_allocator.procedure = default_temp_allocator_proc;
|
||||||
c.temp_allocator.data = &global_scratch_allocator_data;
|
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.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.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.logger.data = nil;
|
||||||
|
|
||||||
c.stdin = os.stdin;
|
c.stdin = os.stdin;
|
||||||
@@ -411,7 +467,7 @@ __init_context :: proc "contextless" (c: ^Context) {
|
|||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
init_global_temporary_allocator :: proc(data: []byte, backup_allocator := context.allocator) {
|
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) {
|
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) {
|
||||||
@@ -491,35 +547,112 @@ resize :: proc{resize_dynamic_array};
|
|||||||
|
|
||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
new :: proc{mem.new};
|
free :: proc{mem_free};
|
||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
new_clone :: proc{mem.new_clone};
|
free_all :: proc{mem_free_all};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@builtin
|
@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
|
@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
|
@builtin
|
||||||
delete :: proc{
|
delete :: proc{
|
||||||
mem.delete_string,
|
delete_string,
|
||||||
mem.delete_cstring,
|
delete_cstring,
|
||||||
mem.delete_dynamic_array,
|
delete_dynamic_array,
|
||||||
mem.delete_slice,
|
delete_slice,
|
||||||
mem.delete_map,
|
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
|
@builtin
|
||||||
make :: proc{
|
make :: proc{
|
||||||
mem.make_slice,
|
make_slice,
|
||||||
mem.make_dynamic_array,
|
make_dynamic_array,
|
||||||
mem.make_dynamic_array_len,
|
make_dynamic_array_len,
|
||||||
mem.make_dynamic_array_len_cap,
|
make_dynamic_array_len_cap,
|
||||||
mem.make_map,
|
make_map,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
||||||
if m == nil do return;
|
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);
|
data := (^E)(a.data);
|
||||||
assert(data != nil);
|
assert(data != nil);
|
||||||
val := arg;
|
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;
|
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);
|
a := (^Raw_Dynamic_Array)(array);
|
||||||
data := (^E)(a.data);
|
data := (^E)(a.data);
|
||||||
assert(data != nil);
|
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;
|
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;
|
type := si.types[i].variant.(Type_Info_Pointer).elem;
|
||||||
max_align = max(max_align, type.align);
|
max_align = max(max_align, type.align);
|
||||||
|
|
||||||
old_size = mem.align_forward_int(old_size, type.align);
|
old_size = align_forward_int(old_size, type.align);
|
||||||
new_size = mem.align_forward_int(new_size, type.align);
|
new_size = align_forward_int(new_size, type.align);
|
||||||
|
|
||||||
old_size += type.size * old_cap;
|
old_size += type.size * old_cap;
|
||||||
new_size += type.size * capacity;
|
new_size += type.size * capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_size = mem.align_forward_int(old_size, max_align);
|
old_size = align_forward_int(old_size, max_align);
|
||||||
new_size = mem.align_forward_int(new_size, max_align);
|
new_size = align_forward_int(new_size, max_align);
|
||||||
|
|
||||||
old_data := (^rawptr)(array)^;
|
old_data := (^rawptr)(array)^;
|
||||||
|
|
||||||
new_data := array.allocator.procedure(
|
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,
|
nil, old_size, 0, loc,
|
||||||
);
|
);
|
||||||
if new_data == nil do return false;
|
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;
|
type := si.types[i].variant.(Type_Info_Pointer).elem;
|
||||||
max_align = max(max_align, type.align);
|
max_align = max(max_align, type.align);
|
||||||
|
|
||||||
old_offset = mem.align_forward_int(old_offset, type.align);
|
old_offset = align_forward_int(old_offset, type.align);
|
||||||
new_offset = mem.align_forward_int(new_offset, type.align);
|
new_offset = align_forward_int(new_offset, type.align);
|
||||||
|
|
||||||
new_data_elem := rawptr(uintptr(new_data) + uintptr(new_offset));
|
new_data_elem := rawptr(uintptr(new_data) + uintptr(new_offset));
|
||||||
old_data_elem := rawptr(uintptr(old_data) + uintptr(old_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.procedure(
|
||||||
array.allocator.data, mem.Allocator_Mode.Free, 0, max_align,
|
array.allocator.data, .Free, 0, max_align,
|
||||||
old_data, old_size, 0, loc,
|
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;
|
type := si.types[i].variant.(Type_Info_Pointer).elem;
|
||||||
max_align = max(max_align, type.align);
|
max_align = max(max_align, type.align);
|
||||||
|
|
||||||
soa_offset = mem.align_forward_int(soa_offset, type.align);
|
soa_offset = align_forward_int(soa_offset, type.align);
|
||||||
item_offset = mem.align_forward_int(item_offset, type.align);
|
item_offset = align_forward_int(item_offset, type.align);
|
||||||
|
|
||||||
dst := rawptr(uintptr(data) + uintptr(soa_offset) + uintptr(type.size * len_ptr^));
|
dst := rawptr(uintptr(data) + uintptr(soa_offset) + uintptr(type.size * len_ptr^));
|
||||||
src := rawptr(uintptr(arg_ptr) + uintptr(item_offset));
|
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;
|
type := si.types[i].variant.(Type_Info_Pointer).elem;
|
||||||
max_align = max(max_align, type.align);
|
max_align = max(max_align, type.align);
|
||||||
|
|
||||||
soa_offset = mem.align_forward_int(soa_offset, type.align);
|
soa_offset = align_forward_int(soa_offset, type.align);
|
||||||
item_offset = mem.align_forward_int(item_offset, type.align);
|
item_offset = align_forward_int(item_offset, type.align);
|
||||||
|
|
||||||
dst := uintptr(data) + uintptr(soa_offset) + uintptr(type.size * len_ptr^);
|
dst := uintptr(data) + uintptr(soa_offset) + uintptr(type.size * len_ptr^);
|
||||||
src := uintptr(args_ptr) + uintptr(item_offset);
|
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;
|
allocator := a.allocator;
|
||||||
|
|
||||||
new_data := allocator.procedure(
|
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,
|
a.data, old_size, 0, loc,
|
||||||
);
|
);
|
||||||
if new_data == nil do return false;
|
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;
|
allocator := a.allocator;
|
||||||
|
|
||||||
new_data := allocator.procedure(
|
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,
|
a.data, old_size, 0, loc,
|
||||||
);
|
);
|
||||||
if new_data == nil do return false;
|
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;
|
new_size := cap * elem_size;
|
||||||
allocator := array.allocator;
|
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;
|
if new_data == nil do return false;
|
||||||
|
|
||||||
array.data = new_data;
|
array.data = new_data;
|
||||||
@@ -1052,7 +1185,7 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
|
|||||||
|
|
||||||
assert(array.data != nil);
|
assert(array.data != nil);
|
||||||
data := uintptr(array.data) + uintptr(elem_size*array.len);
|
data := uintptr(array.data) + uintptr(elem_size*array.len);
|
||||||
mem.zero(rawptr(data), elem_size);
|
mem_zero(rawptr(data), elem_size);
|
||||||
array.len += 1;
|
array.len += 1;
|
||||||
return array.len;
|
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_);
|
array := (^Raw_Slice)(array_);
|
||||||
|
|
||||||
if new_count < array.len do return true;
|
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);
|
old_size := array.len*size_of(T);
|
||||||
new_size := new_count*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;
|
if new_data == nil do return false;
|
||||||
array.data = new_data;
|
array.data = new_data;
|
||||||
array.len = new_count;
|
array.len = new_count;
|
||||||
|
|||||||
@@ -2,6 +2,57 @@ package runtime
|
|||||||
|
|
||||||
import "core:os"
|
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 {
|
mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||||
if src == nil do return dst;
|
if src == nil do return dst;
|
||||||
// NOTE(bill): This _must_ be implemented like C's memmove
|
// 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;
|
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) {
|
print_u64 :: proc(fd: os.Handle, x: u64) {
|
||||||
digits := "0123456789";
|
digits := "0123456789";
|
||||||
|
|
||||||
@@ -380,12 +472,6 @@ memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@private
|
|
||||||
Raw_String :: struct {
|
|
||||||
data: ^byte,
|
|
||||||
len: int,
|
|
||||||
};
|
|
||||||
|
|
||||||
string_eq :: proc "contextless" (a, b: string) -> bool {
|
string_eq :: proc "contextless" (a, b: string) -> bool {
|
||||||
x := transmute(Raw_String)a;
|
x := transmute(Raw_String)a;
|
||||||
y := transmute(Raw_String)b;
|
y := transmute(Raw_String)b;
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^T
|
|||||||
t.procedure(t);
|
t.procedure(t);
|
||||||
|
|
||||||
if !t.use_init_context {
|
if !t.use_init_context {
|
||||||
if context.temp_allocator.data == &runtime.global_scratch_allocator_data {
|
if context.temp_allocator.data == &runtime.global_default_temp_allocator_data {
|
||||||
runtime.global_scratch_allocator_destroy(auto_cast context.temp_allocator.data);
|
runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+62
-46
@@ -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());
|
ptr_set_init(&c->info.minimum_dependency_type_info_set, heap_allocator());
|
||||||
|
|
||||||
String required_runtime_entities[] = {
|
String required_runtime_entities[] = {
|
||||||
|
str_lit("Allocator"),
|
||||||
|
str_lit("Logger"),
|
||||||
|
str_lit("mem_zero"),
|
||||||
|
|
||||||
str_lit("__init_context"),
|
str_lit("__init_context"),
|
||||||
str_lit("default_assertion_failure_proc"),
|
str_lit("default_assertion_failure_proc"),
|
||||||
|
|
||||||
str_lit("args__"),
|
str_lit("args__"),
|
||||||
str_lit("type_table"),
|
str_lit("type_table"),
|
||||||
str_lit("__type_info_of"),
|
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("Type_Info"),
|
||||||
str_lit("Source_Code_Location"),
|
str_lit("Source_Code_Location"),
|
||||||
@@ -1683,6 +1691,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
|||||||
str_lit("umodti3"),
|
str_lit("umodti3"),
|
||||||
str_lit("udivti3"),
|
str_lit("udivti3"),
|
||||||
|
|
||||||
|
str_lit("memset"),
|
||||||
|
|
||||||
str_lit("memory_compare"),
|
str_lit("memory_compare"),
|
||||||
str_lit("memory_compare_zero"),
|
str_lit("memory_compare_zero"),
|
||||||
};
|
};
|
||||||
@@ -1695,7 +1705,6 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
|||||||
// NOTE(bill): Only if these exist
|
// NOTE(bill): Only if these exist
|
||||||
str_lit("memcpy"),
|
str_lit("memcpy"),
|
||||||
str_lit("memmove"),
|
str_lit("memmove"),
|
||||||
str_lit("memset"),
|
|
||||||
str_lit("_tls_index"),
|
str_lit("_tls_index"),
|
||||||
str_lit("_fltused"),
|
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"));
|
AstPackage *os = get_core_package(&c->info, str_lit("os"));
|
||||||
String required_os_entities[] = {
|
String required_os_entities[] = {
|
||||||
str_lit("heap_allocator"),
|
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) {
|
Entity *find_core_entity(Checker *c, String name) {
|
||||||
@@ -1882,6 +1883,10 @@ Type *find_core_type(Checker *c, String name) {
|
|||||||
, LIT(name));
|
, LIT(name));
|
||||||
// NOTE(bill): This will exit the program as it's cannot continue without it!
|
// 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;
|
return e->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2031,7 +2036,7 @@ void init_mem_allocator(Checker *c) {
|
|||||||
if (t_allocator != nullptr) {
|
if (t_allocator != nullptr) {
|
||||||
return;
|
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");
|
String name = str_lit("Allocator");
|
||||||
Entity *e = scope_lookup_current(pkg->scope, name);
|
Entity *e = scope_lookup_current(pkg->scope, name);
|
||||||
@@ -2049,6 +2054,7 @@ void init_core_context(Checker *c) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t_context = find_core_type(c, str_lit("Context"));
|
t_context = find_core_type(c, str_lit("Context"));
|
||||||
|
GB_ASSERT(t_context != nullptr);
|
||||||
t_context_ptr = alloc_type_pointer(t_context);
|
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) {
|
void check_all_global_entities(Checker *c) {
|
||||||
Scope *prev_file = nullptr;
|
Scope *prev_file = nullptr;
|
||||||
|
|
||||||
for_array(i, c->info.entities) {
|
for_array(i, c->info.entities) {
|
||||||
Entity *e = c->info.entities[i];
|
Entity *e = c->info.entities[i];
|
||||||
DeclInfo *d = e->decl_info;
|
DeclInfo *d = e->decl_info;
|
||||||
|
check_single_global_entity(c, e, d);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-6
@@ -3006,11 +3006,13 @@ void ir_emit_zero_init(irProcedure *p, irValue *address, Ast *expr) {
|
|||||||
auto args = array_make<irValue *>(a, 2);
|
auto args = array_make<irValue *>(a, 2);
|
||||||
args[0] = ir_emit_conv(p, address, t_rawptr);
|
args[0] = ir_emit_conv(p, address, t_rawptr);
|
||||||
args[1] = ir_const_int(type_size_of(t));
|
args[1] = ir_const_int(type_size_of(t));
|
||||||
AstPackage *pkg = get_core_package(p->module->info, str_lit("mem"));
|
AstPackage *pkg_runtime = get_core_package(p->module->info, str_lit("runtime"));
|
||||||
if (p->entity != nullptr && p->entity->token.string != "zero" && p->entity->pkg != pkg) {
|
if (p->entity != nullptr) {
|
||||||
ir_emit_comment(p, str_lit("ZeroInit"));
|
if (p->entity->pkg != pkg_runtime && p->entity->token.string != "mem_zero") {
|
||||||
irValue *v = ir_emit_package_call(p, "mem", "zero", args, expr);
|
ir_emit_comment(p, str_lit("ZeroInit"));
|
||||||
return;
|
irValue *v = ir_emit_package_call(p, "runtime", "mem_zero", args, expr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ir_emit(p, ir_instr_zero_init(p, address));
|
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);
|
AstPackage *p = get_core_package(proc->module->info, package_name);
|
||||||
Entity *e = scope_lookup_current(p->scope, name);
|
Entity *e = scope_lookup_current(p->scope, name);
|
||||||
irValue **found = map_get(&proc->module->values, hash_entity(e));
|
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 *gp = *found;
|
||||||
irValue *call = ir_emit_call(proc, gp, args, inlining);
|
irValue *call = ir_emit_call(proc, gp, args, inlining);
|
||||||
return call;
|
return call;
|
||||||
|
|||||||
Reference in New Issue
Block a user