mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-05 10:14:05 +00:00
Move definition of mem.Allocator and log.Logger to package runtime, to reduce import cycle magic
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
108
src/checker.cpp
108
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_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
14
src/ir.cpp
14
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;
|
||||
|
||||
Reference in New Issue
Block a user