mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-30 01:01:49 -07:00
5489a88983
`typeid` used to be a fancy index with extra metadata stored on it. Now it is direct hash of the type. This is safe to do in practice since any possible collisions are checked at compile time AND the chances of having a 1% collision are around 1 in 600K (see the Birthday Paradox). Therefore accessing a `^Type_Info` is now a hash table lookup with linear probing. The table is twice the size than necessary so prevent too much probing due to an overly dense hash table.
763 lines
17 KiB
Odin
763 lines
17 KiB
Odin
// This is the runtime code required by the compiler
|
|
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
|
// The compiler relies upon this _exact_ order
|
|
//
|
|
// Naming Conventions:
|
|
// In general, Ada_Case for types and snake_case for values
|
|
//
|
|
// Package Name: snake_case (but prefer single word)
|
|
// Import Name: snake_case (but prefer single word)
|
|
// Types: Ada_Case
|
|
// Enum Values: Ada_Case
|
|
// Procedures: snake_case
|
|
// Local Variables: snake_case
|
|
// Constant Variables: SCREAMING_SNAKE_CASE
|
|
//
|
|
// IMPORTANT NOTE(bill): `type_info_of` cannot be used within a
|
|
// #shared_global_scope due to the internals of the compiler.
|
|
// This could change at a later date if the all these data structures are
|
|
// implemented within the compiler rather than in this "preload" file
|
|
//
|
|
#+no-instrumentation
|
|
package runtime
|
|
|
|
import "base:intrinsics"
|
|
|
|
// NOTE(bill): This must match the compiler's
|
|
Calling_Convention :: enum u8 {
|
|
Invalid = 0,
|
|
Odin = 1,
|
|
Contextless = 2,
|
|
CDecl = 3,
|
|
Std_Call = 4,
|
|
Fast_Call = 5,
|
|
|
|
None = 6,
|
|
Naked = 7,
|
|
|
|
_ = 8, // reserved
|
|
|
|
Win64 = 9,
|
|
SysV = 10,
|
|
}
|
|
|
|
Type_Info_Enum_Value :: distinct i64
|
|
|
|
Platform_Endianness :: enum u8 {
|
|
Platform = 0,
|
|
Little = 1,
|
|
Big = 2,
|
|
}
|
|
|
|
// Procedure type to test whether two values of the same type are equal
|
|
Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool
|
|
// Procedure type to hash a value, default seed value is 0
|
|
Hasher_Proc :: distinct proc "contextless" (data: rawptr, seed: uintptr = 0) -> uintptr
|
|
|
|
Type_Info_Struct_Soa_Kind :: enum u8 {
|
|
None = 0,
|
|
Fixed = 1,
|
|
Slice = 2,
|
|
Dynamic = 3,
|
|
}
|
|
|
|
// Variant Types
|
|
Type_Info_Named :: struct {
|
|
name: string,
|
|
base: ^Type_Info,
|
|
pkg: string,
|
|
loc: ^Source_Code_Location,
|
|
}
|
|
Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness}
|
|
Type_Info_Rune :: struct {}
|
|
Type_Info_Float :: struct {endianness: Platform_Endianness}
|
|
Type_Info_Complex :: struct {}
|
|
Type_Info_Quaternion :: struct {}
|
|
Type_Info_String :: struct {is_cstring: bool}
|
|
Type_Info_Boolean :: struct {}
|
|
Type_Info_Any :: struct {}
|
|
Type_Info_Type_Id :: struct {}
|
|
Type_Info_Pointer :: struct {
|
|
elem: ^Type_Info, // nil -> rawptr
|
|
}
|
|
Type_Info_Multi_Pointer :: struct {
|
|
elem: ^Type_Info,
|
|
}
|
|
Type_Info_Procedure :: struct {
|
|
params: ^Type_Info, // Type_Info_Parameters
|
|
results: ^Type_Info, // Type_Info_Parameters
|
|
variadic: bool,
|
|
convention: Calling_Convention,
|
|
}
|
|
Type_Info_Array :: struct {
|
|
elem: ^Type_Info,
|
|
elem_size: int,
|
|
count: int,
|
|
}
|
|
Type_Info_Enumerated_Array :: struct {
|
|
elem: ^Type_Info,
|
|
index: ^Type_Info,
|
|
elem_size: int,
|
|
count: int,
|
|
min_value: Type_Info_Enum_Value,
|
|
max_value: Type_Info_Enum_Value,
|
|
is_sparse: bool,
|
|
}
|
|
Type_Info_Dynamic_Array :: struct {elem: ^Type_Info, elem_size: int}
|
|
Type_Info_Slice :: struct {elem: ^Type_Info, elem_size: int}
|
|
|
|
Type_Info_Parameters :: struct { // Only used for procedures parameters and results
|
|
types: []^Type_Info,
|
|
names: []string,
|
|
}
|
|
Type_Info_Tuple :: Type_Info_Parameters // Will be removed eventually
|
|
|
|
Type_Info_Struct_Flags :: distinct bit_set[Type_Info_Struct_Flag; u8]
|
|
Type_Info_Struct_Flag :: enum u8 {
|
|
packed = 0,
|
|
raw_union = 1,
|
|
no_copy = 2,
|
|
align = 3,
|
|
}
|
|
|
|
Type_Info_Struct :: struct {
|
|
// Slice these with `field_count`
|
|
types: [^]^Type_Info `fmt:"v,field_count"`,
|
|
names: [^]string `fmt:"v,field_count"`,
|
|
offsets: [^]uintptr `fmt:"v,field_count"`,
|
|
usings: [^]bool `fmt:"v,field_count"`,
|
|
tags: [^]string `fmt:"v,field_count"`,
|
|
|
|
field_count: i32,
|
|
|
|
flags: Type_Info_Struct_Flags,
|
|
|
|
// These are only set iff this structure is an SOA structure
|
|
soa_kind: Type_Info_Struct_Soa_Kind,
|
|
soa_len: i32,
|
|
soa_base_type: ^Type_Info,
|
|
|
|
equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set
|
|
}
|
|
Type_Info_Union :: struct {
|
|
variants: []^Type_Info,
|
|
tag_offset: uintptr,
|
|
tag_type: ^Type_Info,
|
|
|
|
equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set
|
|
|
|
custom_align: bool,
|
|
no_nil: bool,
|
|
shared_nil: bool,
|
|
}
|
|
Type_Info_Enum :: struct {
|
|
base: ^Type_Info,
|
|
names: []string,
|
|
values: []Type_Info_Enum_Value,
|
|
}
|
|
Type_Info_Map :: struct {
|
|
key: ^Type_Info,
|
|
value: ^Type_Info,
|
|
map_info: ^Map_Info,
|
|
}
|
|
Type_Info_Bit_Set :: struct {
|
|
elem: ^Type_Info,
|
|
underlying: ^Type_Info, // Possibly nil
|
|
lower: i64,
|
|
upper: i64,
|
|
}
|
|
Type_Info_Simd_Vector :: struct {
|
|
elem: ^Type_Info,
|
|
elem_size: int,
|
|
count: int,
|
|
}
|
|
Type_Info_Matrix :: struct {
|
|
elem: ^Type_Info,
|
|
elem_size: int,
|
|
elem_stride: int, // elem_stride >= row_count
|
|
row_count: int,
|
|
column_count: int,
|
|
// Total element count = column_count * elem_stride
|
|
layout: enum u8 {
|
|
Column_Major, // array of column vectors
|
|
Row_Major, // array of row vectors
|
|
},
|
|
}
|
|
Type_Info_Soa_Pointer :: struct {
|
|
elem: ^Type_Info,
|
|
}
|
|
Type_Info_Bit_Field :: struct {
|
|
backing_type: ^Type_Info,
|
|
names: [^]string `fmt:"v,field_count"`,
|
|
types: [^]^Type_Info `fmt:"v,field_count"`,
|
|
bit_sizes: [^]uintptr `fmt:"v,field_count"`,
|
|
bit_offsets: [^]uintptr `fmt:"v,field_count"`,
|
|
tags: [^]string `fmt:"v,field_count"`,
|
|
field_count: int,
|
|
}
|
|
|
|
Type_Info_Flag :: enum u8 {
|
|
Comparable = 0,
|
|
Simple_Compare = 1,
|
|
}
|
|
Type_Info_Flags :: distinct bit_set[Type_Info_Flag; u32]
|
|
|
|
Type_Info :: struct {
|
|
size: int,
|
|
align: int,
|
|
flags: Type_Info_Flags,
|
|
id: typeid,
|
|
|
|
variant: union {
|
|
Type_Info_Named,
|
|
Type_Info_Integer,
|
|
Type_Info_Rune,
|
|
Type_Info_Float,
|
|
Type_Info_Complex,
|
|
Type_Info_Quaternion,
|
|
Type_Info_String,
|
|
Type_Info_Boolean,
|
|
Type_Info_Any,
|
|
Type_Info_Type_Id,
|
|
Type_Info_Pointer,
|
|
Type_Info_Multi_Pointer,
|
|
Type_Info_Procedure,
|
|
Type_Info_Array,
|
|
Type_Info_Enumerated_Array,
|
|
Type_Info_Dynamic_Array,
|
|
Type_Info_Slice,
|
|
Type_Info_Parameters,
|
|
Type_Info_Struct,
|
|
Type_Info_Union,
|
|
Type_Info_Enum,
|
|
Type_Info_Map,
|
|
Type_Info_Bit_Set,
|
|
Type_Info_Simd_Vector,
|
|
Type_Info_Matrix,
|
|
Type_Info_Soa_Pointer,
|
|
Type_Info_Bit_Field,
|
|
},
|
|
}
|
|
|
|
// NOTE(bill): only the ones that are needed (not all types)
|
|
// This will be set by the compiler
|
|
type_table: []^Type_Info
|
|
|
|
args__: []cstring
|
|
|
|
when ODIN_OS == .Windows {
|
|
// NOTE(Jeroen): If we're a Windows DLL, fwdReason will be populated.
|
|
// This tells a DLL if it's first loaded, about to be unloaded, or a thread is joining/exiting.
|
|
|
|
DLL_Forward_Reason :: enum u32 {
|
|
Process_Detach = 0, // About to unload DLL
|
|
Process_Attach = 1, // Entry point
|
|
Thread_Attach = 2,
|
|
Thread_Detach = 3,
|
|
}
|
|
dll_forward_reason: DLL_Forward_Reason
|
|
|
|
dll_instance: rawptr
|
|
}
|
|
|
|
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
|
|
|
|
|
|
Source_Code_Location :: struct {
|
|
file_path: string,
|
|
line, column: i32,
|
|
procedure: string,
|
|
}
|
|
|
|
/*
|
|
Used by the built-in directory `#load_directory(path: string) -> []Load_Directory_File`
|
|
*/
|
|
Load_Directory_File :: struct {
|
|
name: string,
|
|
data: []byte, // immutable data
|
|
}
|
|
|
|
Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location) -> !
|
|
|
|
// Allocation Stuff
|
|
Allocator_Mode :: enum byte {
|
|
Alloc,
|
|
Free,
|
|
Free_All,
|
|
Resize,
|
|
Query_Features,
|
|
Query_Info,
|
|
Alloc_Non_Zeroed,
|
|
Resize_Non_Zeroed,
|
|
}
|
|
|
|
Allocator_Mode_Set :: distinct bit_set[Allocator_Mode]
|
|
|
|
Allocator_Query_Info :: struct {
|
|
pointer: rawptr,
|
|
size: Maybe(int),
|
|
alignment: Maybe(int),
|
|
}
|
|
|
|
Allocator_Error :: enum byte {
|
|
None = 0,
|
|
Out_Of_Memory = 1,
|
|
Invalid_Pointer = 2,
|
|
Invalid_Argument = 3,
|
|
Mode_Not_Implemented = 4,
|
|
}
|
|
|
|
Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|
size, alignment: int,
|
|
old_memory: rawptr, old_size: int,
|
|
location: Source_Code_Location = #caller_location) -> ([]byte, Allocator_Error)
|
|
Allocator :: struct {
|
|
procedure: Allocator_Proc,
|
|
data: rawptr,
|
|
}
|
|
|
|
Byte :: 1
|
|
Kilobyte :: 1024 * Byte
|
|
Megabyte :: 1024 * Kilobyte
|
|
Gigabyte :: 1024 * Megabyte
|
|
Terabyte :: 1024 * Gigabyte
|
|
Petabyte :: 1024 * Terabyte
|
|
Exabyte :: 1024 * Petabyte
|
|
|
|
// Logging stuff
|
|
|
|
Logger_Level :: enum uint {
|
|
Debug = 0,
|
|
Info = 10,
|
|
Warning = 20,
|
|
Error = 30,
|
|
Fatal = 40,
|
|
}
|
|
|
|
Logger_Option :: enum {
|
|
Level,
|
|
Date,
|
|
Time,
|
|
Short_File_Path,
|
|
Long_File_Path,
|
|
Line,
|
|
Procedure,
|
|
Terminal_Color,
|
|
Thread_Id,
|
|
}
|
|
|
|
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,
|
|
lowest_level: Logger_Level,
|
|
options: Logger_Options,
|
|
}
|
|
|
|
|
|
Random_Generator_Mode :: enum {
|
|
Read,
|
|
Reset,
|
|
Query_Info,
|
|
}
|
|
|
|
Random_Generator_Query_Info_Flag :: enum u32 {
|
|
Cryptographic,
|
|
Uniform,
|
|
External_Entropy,
|
|
Resettable,
|
|
}
|
|
Random_Generator_Query_Info :: distinct bit_set[Random_Generator_Query_Info_Flag; u32]
|
|
|
|
Random_Generator_Proc :: #type proc(data: rawptr, mode: Random_Generator_Mode, p: []byte)
|
|
|
|
Random_Generator :: struct {
|
|
procedure: Random_Generator_Proc,
|
|
data: rawptr,
|
|
}
|
|
|
|
Context :: struct {
|
|
allocator: Allocator,
|
|
temp_allocator: Allocator,
|
|
assertion_failure_proc: Assertion_Failure_Proc,
|
|
logger: Logger,
|
|
random_generator: Random_Generator,
|
|
|
|
user_ptr: rawptr,
|
|
user_index: int,
|
|
|
|
// Internal use only
|
|
_internal: rawptr,
|
|
}
|
|
|
|
|
|
Raw_String :: struct {
|
|
data: [^]byte,
|
|
len: int,
|
|
}
|
|
|
|
Raw_Slice :: struct {
|
|
data: rawptr,
|
|
len: int,
|
|
}
|
|
|
|
Raw_Dynamic_Array :: struct {
|
|
data: rawptr,
|
|
len: int,
|
|
cap: int,
|
|
allocator: Allocator,
|
|
}
|
|
|
|
// The raw, type-erased representation of a map.
|
|
//
|
|
// 32-bytes on 64-bit
|
|
// 16-bytes on 32-bit
|
|
Raw_Map :: struct {
|
|
// A single allocation spanning all keys, values, and hashes.
|
|
// {
|
|
// k: Map_Cell(K) * (capacity / ks_per_cell)
|
|
// v: Map_Cell(V) * (capacity / vs_per_cell)
|
|
// h: Map_Cell(H) * (capacity / hs_per_cell)
|
|
// }
|
|
//
|
|
// The data is allocated assuming 64-byte alignment, meaning the address is
|
|
// always a multiple of 64. This means we have 6 bits of zeros in the pointer
|
|
// to store the capacity. We can store a value as large as 2^6-1 or 63 in
|
|
// there. This conveniently is the maximum log2 capacity we can have for a map
|
|
// as Odin uses signed integers to represent capacity.
|
|
//
|
|
// Since the hashes are backed by Map_Hash, which is just a 64-bit unsigned
|
|
// integer, the cell structure for hashes is unnecessary because 64/8 is 8 and
|
|
// requires no padding, meaning it can be indexed as a regular array of
|
|
// Map_Hash directly, though for consistency sake it's written as if it were
|
|
// an array of Map_Cell(Map_Hash).
|
|
data: uintptr, // 8-bytes on 64-bits, 4-bytes on 32-bits
|
|
len: uintptr, // 8-bytes on 64-bits, 4-bytes on 32-bits
|
|
allocator: Allocator, // 16-bytes on 64-bits, 8-bytes on 32-bits
|
|
}
|
|
|
|
Raw_Any :: struct {
|
|
data: rawptr,
|
|
id: typeid,
|
|
}
|
|
|
|
Raw_Cstring :: struct {
|
|
data: [^]byte,
|
|
}
|
|
|
|
Raw_Soa_Pointer :: struct {
|
|
data: rawptr,
|
|
index: int,
|
|
}
|
|
|
|
Raw_Complex32 :: struct {real, imag: f16}
|
|
Raw_Complex64 :: struct {real, imag: f32}
|
|
Raw_Complex128 :: struct {real, imag: f64}
|
|
Raw_Quaternion64 :: struct {imag, jmag, kmag: f16, real: f16}
|
|
Raw_Quaternion128 :: struct {imag, jmag, kmag: f32, real: f32}
|
|
Raw_Quaternion256 :: struct {imag, jmag, kmag: f64, real: f64}
|
|
Raw_Quaternion64_Vector_Scalar :: struct {vector: [3]f16, scalar: f16}
|
|
Raw_Quaternion128_Vector_Scalar :: struct {vector: [3]f32, scalar: f32}
|
|
Raw_Quaternion256_Vector_Scalar :: struct {vector: [3]f64, scalar: f64}
|
|
|
|
|
|
/*
|
|
// Defined internally by the compiler
|
|
Odin_OS_Type :: enum int {
|
|
Unknown,
|
|
Windows,
|
|
Darwin,
|
|
Linux,
|
|
Essence,
|
|
FreeBSD,
|
|
OpenBSD,
|
|
NetBSD,
|
|
Haiku,
|
|
WASI,
|
|
JS,
|
|
Orca,
|
|
Freestanding,
|
|
}
|
|
*/
|
|
Odin_OS_Type :: type_of(ODIN_OS)
|
|
|
|
/*
|
|
// Defined internally by the compiler
|
|
Odin_Arch_Type :: enum int {
|
|
Unknown,
|
|
amd64,
|
|
i386,
|
|
arm32,
|
|
arm64,
|
|
wasm32,
|
|
wasm64p32,
|
|
riscv64,
|
|
}
|
|
*/
|
|
Odin_Arch_Type :: type_of(ODIN_ARCH)
|
|
|
|
Odin_Arch_Types :: bit_set[Odin_Arch_Type]
|
|
|
|
ALL_ODIN_ARCH_TYPES :: Odin_Arch_Types{
|
|
.amd64,
|
|
.i386,
|
|
.arm32,
|
|
.arm64,
|
|
.wasm32,
|
|
.wasm64p32,
|
|
.riscv64,
|
|
}
|
|
|
|
/*
|
|
// Defined internally by the compiler
|
|
Odin_Build_Mode_Type :: enum int {
|
|
Executable,
|
|
Dynamic,
|
|
Static,
|
|
Object,
|
|
Assembly,
|
|
LLVM_IR,
|
|
}
|
|
*/
|
|
Odin_Build_Mode_Type :: type_of(ODIN_BUILD_MODE)
|
|
|
|
/*
|
|
// Defined internally by the compiler
|
|
Odin_Endian_Type :: enum int {
|
|
Unknown,
|
|
Little,
|
|
Big,
|
|
}
|
|
*/
|
|
Odin_Endian_Type :: type_of(ODIN_ENDIAN)
|
|
|
|
Odin_OS_Types :: bit_set[Odin_OS_Type]
|
|
|
|
ALL_ODIN_OS_TYPES :: Odin_OS_Types{
|
|
.Windows,
|
|
.Darwin,
|
|
.Linux,
|
|
.Essence,
|
|
.FreeBSD,
|
|
.OpenBSD,
|
|
.NetBSD,
|
|
.Haiku,
|
|
.WASI,
|
|
.JS,
|
|
.Orca,
|
|
.Freestanding,
|
|
}
|
|
|
|
/*
|
|
// Defined internally by the compiler
|
|
Odin_Platform_Subtarget_Type :: enum int {
|
|
Default,
|
|
iOS,
|
|
}
|
|
*/
|
|
Odin_Platform_Subtarget_Type :: type_of(ODIN_PLATFORM_SUBTARGET)
|
|
|
|
/*
|
|
// Defined internally by the compiler
|
|
Odin_Sanitizer_Flag :: enum u32 {
|
|
Address = 0,
|
|
Memory = 1,
|
|
Thread = 2,
|
|
}
|
|
Odin_Sanitizer_Flags :: distinct bit_set[Odin_Sanitizer_Flag; u32]
|
|
|
|
ODIN_SANITIZER_FLAGS // is a constant
|
|
*/
|
|
Odin_Sanitizer_Flags :: type_of(ODIN_SANITIZER_FLAGS)
|
|
|
|
/*
|
|
// Defined internally by the compiler
|
|
Odin_Optimization_Mode :: enum int {
|
|
None = -1,
|
|
Minimal = 0,
|
|
Size = 1,
|
|
Speed = 2,
|
|
Aggressive = 3,
|
|
}
|
|
|
|
ODIN_OPTIMIZATION_MODE // is a constant
|
|
*/
|
|
Odin_Optimization_Mode :: type_of(ODIN_OPTIMIZATION_MODE)
|
|
|
|
/////////////////////////////
|
|
// Init Startup Procedures //
|
|
/////////////////////////////
|
|
|
|
// IMPORTANT NOTE(bill): Do not call this unless you want to explicitly set up the entry point and how it gets called
|
|
// This is probably only useful for freestanding targets
|
|
foreign {
|
|
@(link_name="__$startup_runtime")
|
|
_startup_runtime :: proc "odin" () ---
|
|
@(link_name="__$cleanup_runtime")
|
|
_cleanup_runtime :: proc "odin" () ---
|
|
}
|
|
|
|
_cleanup_runtime_contextless :: proc "contextless" () {
|
|
context = default_context()
|
|
_cleanup_runtime()
|
|
}
|
|
|
|
|
|
/////////////////////////////
|
|
/////////////////////////////
|
|
/////////////////////////////
|
|
|
|
|
|
type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
|
if info == nil {
|
|
return nil
|
|
}
|
|
|
|
base := info
|
|
loop: for {
|
|
#partial switch i in base.variant {
|
|
case Type_Info_Named: base = i.base
|
|
case: break loop
|
|
}
|
|
}
|
|
return base
|
|
}
|
|
|
|
|
|
type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
|
if info == nil {
|
|
return nil
|
|
}
|
|
|
|
base := info
|
|
loop: for {
|
|
#partial switch i in base.variant {
|
|
case Type_Info_Named: base = i.base
|
|
case Type_Info_Enum: base = i.base
|
|
case Type_Info_Bit_Field: base = i.backing_type
|
|
case: break loop
|
|
}
|
|
}
|
|
return base
|
|
}
|
|
type_info_base_without_enum :: type_info_core
|
|
|
|
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check {
|
|
n := u64(len(type_table))
|
|
i := transmute(u64)id % n
|
|
for k in 0..<n {
|
|
ptr := type_table[i]
|
|
if ptr != nil && ptr.id == id {
|
|
return ptr
|
|
}
|
|
i = i+1 if i+1 < n else 0
|
|
}
|
|
return type_table[0]
|
|
}
|
|
|
|
when !ODIN_NO_RTTI {
|
|
typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
|
ti := type_info_of(id)
|
|
ti = type_info_base(ti)
|
|
return ti.id
|
|
}
|
|
typeid_core :: proc "contextless" (id: typeid) -> typeid {
|
|
ti := type_info_core(type_info_of(id))
|
|
return ti.id
|
|
}
|
|
typeid_base_without_enum :: typeid_core
|
|
}
|
|
|
|
|
|
|
|
debug_trap :: intrinsics.debug_trap
|
|
trap :: intrinsics.trap
|
|
read_cycle_counter :: intrinsics.read_cycle_counter
|
|
|
|
|
|
|
|
default_logger_proc :: proc(data: rawptr, level: Logger_Level, text: string, options: Logger_Options, location := #caller_location) {
|
|
// Nothing
|
|
}
|
|
|
|
default_logger :: proc() -> Logger {
|
|
return Logger{default_logger_proc, nil, Logger_Level.Debug, nil}
|
|
}
|
|
|
|
|
|
default_context :: proc "contextless" () -> Context {
|
|
c: Context
|
|
__init_context(&c)
|
|
return c
|
|
}
|
|
|
|
@private
|
|
__init_context_from_ptr :: proc "contextless" (c: ^Context, other: ^Context) {
|
|
if c == nil {
|
|
return
|
|
}
|
|
c^ = other^
|
|
__init_context(c)
|
|
}
|
|
|
|
@private
|
|
__init_context :: proc "contextless" (c: ^Context) {
|
|
if c == nil {
|
|
return
|
|
}
|
|
|
|
// NOTE(bill): Do not initialize these procedures with a call as they are not defined with the "contextless" calling convention
|
|
c.allocator.procedure = default_allocator_proc
|
|
c.allocator.data = nil
|
|
|
|
c.temp_allocator.procedure = default_temp_allocator_proc
|
|
when !NO_DEFAULT_TEMP_ALLOCATOR {
|
|
c.temp_allocator.data = &global_default_temp_allocator_data
|
|
}
|
|
|
|
when !ODIN_DISABLE_ASSERT {
|
|
c.assertion_failure_proc = default_assertion_failure_proc
|
|
}
|
|
|
|
c.logger.procedure = default_logger_proc
|
|
c.logger.data = nil
|
|
|
|
c.random_generator.procedure = default_random_generator_proc
|
|
c.random_generator.data = nil
|
|
}
|
|
|
|
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
|
|
default_assertion_contextless_failure_proc(prefix, message, loc)
|
|
}
|
|
|
|
default_assertion_contextless_failure_proc :: proc "contextless" (prefix, message: string, loc: Source_Code_Location) -> ! {
|
|
when ODIN_OS == .Freestanding {
|
|
// Do nothing
|
|
} else {
|
|
when ODIN_OS != .Orca && !ODIN_DISABLE_ASSERT {
|
|
print_caller_location(loc)
|
|
print_string(" ")
|
|
}
|
|
print_string(prefix)
|
|
if len(message) > 0 {
|
|
print_string(": ")
|
|
print_string(message)
|
|
}
|
|
|
|
when ODIN_OS == .Orca {
|
|
assert_fail(
|
|
cstring(raw_data(loc.file_path)),
|
|
cstring(raw_data(loc.procedure)),
|
|
loc.line,
|
|
"",
|
|
cstring(raw_data(orca_stderr_buffer[:orca_stderr_buffer_idx])),
|
|
)
|
|
} else {
|
|
print_byte('\n')
|
|
}
|
|
}
|
|
trap()
|
|
}
|