123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649 |
- // 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
- //
- package runtime
- import "core: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_Tuple
- results: ^Type_Info, // Type_Info_Tuple
- 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_Tuple :: struct { // Only used for procedures parameters and results
- types: []^Type_Info,
- names: []string,
- }
- Type_Info_Struct :: struct {
- types: []^Type_Info,
- names: []string,
- offsets: []uintptr,
- usings: []bool,
- tags: []string,
- is_packed: bool,
- is_raw_union: bool,
- custom_align: bool,
- equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set
- // These are only set iff this structure is an SOA structure
- soa_kind: Type_Info_Struct_Soa_Kind,
- soa_base_type: ^Type_Info,
- soa_len: int,
- }
- 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_Relative_Pointer :: struct {
- pointer: ^Type_Info,
- base_integer: ^Type_Info,
- }
- Type_Info_Relative_Slice :: struct {
- slice: ^Type_Info,
- base_integer: ^Type_Info,
- }
- 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
- }
- Type_Info_Soa_Pointer :: struct {
- elem: ^Type_Info,
- }
- 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_Tuple,
- Type_Info_Struct,
- Type_Info_Union,
- Type_Info_Enum,
- Type_Info_Map,
- Type_Info_Bit_Set,
- Type_Info_Simd_Vector,
- Type_Info_Relative_Pointer,
- Type_Info_Relative_Slice,
- Type_Info_Matrix,
- Type_Info_Soa_Pointer,
- },
- }
- // NOTE(bill): This must match the compiler's
- Typeid_Kind :: enum u8 {
- Invalid,
- Integer,
- Rune,
- Float,
- Complex,
- Quaternion,
- String,
- Boolean,
- Any,
- Type_Id,
- Pointer,
- Multi_Pointer,
- Procedure,
- Array,
- Enumerated_Array,
- Dynamic_Array,
- Slice,
- Tuple,
- Struct,
- Union,
- Enum,
- Map,
- Bit_Set,
- Simd_Vector,
- Relative_Pointer,
- Relative_Slice,
- Matrix,
- }
- #assert(len(Typeid_Kind) < 32)
- // Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
- // index: 8*size_of(uintptr) - 8,
- // kind: 5, // Typeid_Kind
- // named: 1,
- // special: 1, // signed, cstring, etc
- // reserved: 1,
- // }
- // #assert(size_of(Typeid_Bit_Field) == size_of(uintptr));
- // 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
- }
- // 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,
- }
- 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,
- }
- 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
- // 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,
- }
- Context :: struct {
- allocator: Allocator,
- temp_allocator: Allocator,
- assertion_failure_proc: Assertion_Failure_Proc,
- logger: Logger,
- 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: int, // 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,
- }
- /*
- // Defined internally by the compiler
- Odin_OS_Type :: enum int {
- Unknown,
- Windows,
- Darwin,
- Linux,
- Essence,
- FreeBSD,
- OpenBSD,
- WASI,
- JS,
- Freestanding,
- }
- */
- Odin_OS_Type :: type_of(ODIN_OS)
- /*
- // Defined internally by the compiler
- Odin_Arch_Type :: enum int {
- Unknown,
- amd64,
- i386,
- arm32,
- arm64,
- wasm32,
- wasm64,
- }
- */
- Odin_Arch_Type :: type_of(ODIN_ARCH)
- /*
- // Defined internally by the compiler
- Odin_Build_Mode_Type :: enum int {
- Executable,
- Dynamic,
- 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)
- /////////////////////////////
- // 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() {
- default_temp_allocator_destroy(&global_default_temp_allocator_data)
- }
- _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: break loop
- }
- }
- return base
- }
- type_info_base_without_enum :: type_info_core
- __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check {
- MASK :: 1<<(8*size_of(typeid) - 8) - 1
- data := transmute(uintptr)id
- n := int(data & MASK)
- if n < 0 || n >= len(type_table) {
- n = 0
- }
- return &type_table[n]
- }
- when !ODIN_DISALLOW_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
- 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
- }
- default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
- when ODIN_OS == .Freestanding {
- // Do nothing
- } else {
- print_caller_location(loc)
- print_string(" ")
- print_string(prefix)
- if len(message) > 0 {
- print_string(": ")
- print_string(message)
- }
- print_byte('\n')
- }
- trap()
- }
|