From 399c3ab067d0bbacbf9732107b932d5bb910b67f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jul 2024 21:37:35 +0100 Subject: [PATCH] Reduce the size of `runtime.Type_Info` --- base/runtime/core.odin | 52 +++++++++++++++++------------ base/runtime/print.odin | 11 ++++--- core/encoding/cbor/marshal.odin | 6 ++-- core/encoding/cbor/unmarshal.odin | 2 +- core/encoding/json/marshal.odin | 2 +- core/encoding/json/unmarshal.odin | 2 +- core/fmt/fmt.odin | 16 ++++----- core/reflect/reflect.odin | 26 +++++++-------- core/reflect/types.odin | 27 ++++++++------- src/llvm_backend_const.cpp | 9 +++++ src/llvm_backend_type.cpp | 55 ++++++++++++++++--------------- 11 files changed, 114 insertions(+), 94 deletions(-) diff --git a/base/runtime/core.odin b/base/runtime/core.odin index a758a2fdd..f9bf57259 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -66,7 +66,7 @@ Type_Info_Named :: struct { name: string, base: ^Type_Info, pkg: string, - loc: Source_Code_Location, + loc: ^Source_Code_Location, } Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness} Type_Info_Rune :: struct {} @@ -112,23 +112,32 @@ Type_Info_Parameters :: struct { // Only used for procedures parameters and resu } Type_Info_Tuple :: Type_Info_Parameters // Will be removed eventually -Type_Info_Struct :: struct { - types: []^Type_Info, - names: []string, - offsets: []uintptr, - usings: []bool, - tags: []string, - is_packed: bool, - is_raw_union: bool, - is_no_copy: bool, - custom_align: bool, +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, +} - equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set +Type_Info_Struct :: struct { + // Slice these with `field_count` + types: [^]^Type_Info, + names: [^]string, + offsets: [^]uintptr, + usings: [^]bool, + tags: [^]string, + + 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, - soa_len: int, + + 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, @@ -142,9 +151,9 @@ Type_Info_Union :: struct { shared_nil: bool, } Type_Info_Enum :: struct { - base: ^Type_Info, - names: []string, - values: []Type_Info_Enum_Value, + base: ^Type_Info, + names: []string, + values: []Type_Info_Enum_Value, } Type_Info_Map :: struct { key: ^Type_Info, @@ -187,11 +196,12 @@ Type_Info_Soa_Pointer :: struct { } Type_Info_Bit_Field :: struct { backing_type: ^Type_Info, - names: []string, - types: []^Type_Info, - bit_sizes: []uintptr, - bit_offsets: []uintptr, - tags: []string, + names: [^]string, + types: [^]^Type_Info, + bit_sizes: [^]uintptr, + bit_offsets: [^]uintptr, + tags: [^]string, + field_count: int, } Type_Info_Flag :: enum u8 { diff --git a/base/runtime/print.odin b/base/runtime/print.odin index 0262e8ef6..45f6f01ef 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -401,15 +401,16 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { } print_string("struct ") - if info.is_packed { print_string("#packed ") } - if info.is_raw_union { print_string("#raw_union ") } - if info.custom_align { + if .packed in info.flags { print_string("#packed ") } + if .raw_union in info.flags { print_string("#raw_union ") } + if .no_copy in info.flags { print_string("#no_copy ") } + if .align in info.flags { print_string("#align(") print_u64(u64(ti.align)) print_string(") ") } print_byte('{') - for name, i in info.names { + for name, i in info.names[:info.field_count] { if i > 0 { print_string(", ") } print_string(name) print_string(": ") @@ -469,7 +470,7 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_string("bit_field ") print_type(info.backing_type) print_string(" {") - for name, i in info.names { + for name, i in info.names[:info.field_count] { if i > 0 { print_string(", ") } print_string(name) print_string(": ") diff --git a/core/encoding/cbor/marshal.odin b/core/encoding/cbor/marshal.odin index 2cdf384c3..022e297e9 100644 --- a/core/encoding/cbor/marshal.odin +++ b/core/encoding/cbor/marshal.odin @@ -506,7 +506,7 @@ _marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (er } n: u64; { - for _, i in info.names { + for _, i in info.names[:info.field_count] { if field_name(info, i) != "-" { n += 1 } @@ -522,7 +522,7 @@ _marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (er entries := make([dynamic]Name, 0, n, e.temp_allocator) or_return defer delete(entries) - for _, i in info.names { + for _, i in info.names[:info.field_count] { fname := field_name(info, i) if fname == "-" { continue @@ -540,7 +540,7 @@ _marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (er marshal_entry(e, info, v, entry.name, entry.field) or_return } } else { - for _, i in info.names { + for _, i in info.names[:info.field_count] { fname := field_name(info, i) if fname == "-" { continue diff --git a/core/encoding/cbor/unmarshal.odin b/core/encoding/cbor/unmarshal.odin index 13350bb85..4da2d5a93 100644 --- a/core/encoding/cbor/unmarshal.odin +++ b/core/encoding/cbor/unmarshal.odin @@ -618,7 +618,7 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, #partial switch t in ti.variant { case reflect.Type_Info_Struct: - if t.is_raw_union { + if .raw_union in t.flags { return _unsupported(v, hdr) } diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 30426f911..fa86d3468 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -406,7 +406,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: ti := runtime.type_info_base(type_info_of(v.id)) info := ti.variant.(runtime.Type_Info_Struct) first_iteration := true - for name, i in info.names { + for name, i in info.names[:info.field_count] { omitempty := false json_name, extra := json_name_from_tag_value(reflect.struct_tag_get(reflect.Struct_Tag(info.tags[i]), "json")) diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index eb59e7838..344d2973e 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -368,7 +368,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm #partial switch t in ti.variant { case reflect.Type_Info_Struct: - if t.is_raw_union { + if .raw_union in t.flags { return UNSUPPORTED_TYPE } diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 234f4afbd..ef0647462 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1861,7 +1861,7 @@ handle_tag :: proc(state: ^Info_State, data: rawptr, info: reflect.Type_Info_Str if optional_len == nil { return } - for f, i in info.names { + for f, i in info.names[:info.field_count] { if f != field_name { continue } @@ -1965,7 +1965,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St fmt_bad_verb(fi, the_verb) return } - if info.is_raw_union { + if .raw_union in info.flags { if type_name == "" { io.write_string(fi.writer, "(raw union)", &fi.n) } else { @@ -1989,7 +1989,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St // fi.hash = false; fi.indent += 1 - is_empty := len(info.names) == 0 + is_empty := info.field_count == 0 if !is_soa && hash && !is_empty { io.write_byte(fi.writer, '\n', &fi.n) @@ -2010,17 +2010,17 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St base_type_name = v.name } - actual_field_count := len(info.names) + actual_field_count := info.field_count n := uintptr(info.soa_len) if info.soa_kind == .Slice { - actual_field_count = len(info.names)-1 // len + actual_field_count = info.field_count-1 // len n = uintptr((^int)(uintptr(v.data) + info.offsets[actual_field_count])^) } else if info.soa_kind == .Dynamic { - actual_field_count = len(info.names)-3 // len, cap, allocator + actual_field_count = info.field_count-3 // len, cap, allocator n = uintptr((^int)(uintptr(v.data) + info.offsets[actual_field_count])^) } @@ -2099,7 +2099,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St } } else { field_count := -1 - for name, i in info.names { + for name, i in info.names[:info.field_count] { optional_len: int = -1 use_nul_termination: bool = false verb := the_verb if the_verb == 'w' else 'v' @@ -2605,7 +2605,7 @@ fmt_bit_field :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Bit field_count := -1 - for name, i in info.names { + for name, i in info.names[:info.field_count] { field_verb := verb if handle_bit_field_tag(v.data, info, i, &field_verb) { continue diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 332d91c6e..e6d2bc87a 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -391,7 +391,7 @@ Struct_Field :: struct { struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) { ti := runtime.type_info_base(type_info_of(T)) if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { - if 0 <= i && i < len(s.names) { + if 0 <= i && i < int(s.field_count) { field.name = s.names[i] field.type = s.types[i] field.tag = Struct_Tag(s.tags[i]) @@ -406,7 +406,7 @@ struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) { struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) { ti := runtime.type_info_base(type_info_of(T)) if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { - for fname, i in s.names { + for fname, i in s.names[:s.field_count] { if fname == name { field.name = s.names[i] field.type = s.types[i] @@ -427,7 +427,7 @@ struct_field_value_by_name :: proc(a: any, field: string, allow_using := false) ti := runtime.type_info_base(type_info_of(a.id)) if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { - for name, i in s.names { + for name, i in s.names[:s.field_count] { if name == field { return any{ rawptr(uintptr(a.data) + s.offsets[i]), @@ -463,7 +463,7 @@ struct_field_value :: proc(a: any, field: Struct_Field) -> any { struct_field_names :: proc(T: typeid) -> []string { ti := runtime.type_info_base(type_info_of(T)) if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { - return s.names + return s.names[:s.field_count] } return nil } @@ -472,7 +472,7 @@ struct_field_names :: proc(T: typeid) -> []string { struct_field_types :: proc(T: typeid) -> []^Type_Info { ti := runtime.type_info_base(type_info_of(T)) if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { - return s.types + return s.types[:s.field_count] } return nil } @@ -482,7 +482,7 @@ struct_field_types :: proc(T: typeid) -> []^Type_Info { struct_field_tags :: proc(T: typeid) -> []Struct_Tag { ti := runtime.type_info_base(type_info_of(T)) if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { - return transmute([]Struct_Tag)s.tags + return transmute([]Struct_Tag)s.tags[:s.field_count] } return nil } @@ -491,7 +491,7 @@ struct_field_tags :: proc(T: typeid) -> []Struct_Tag { struct_field_offsets :: proc(T: typeid) -> []uintptr { ti := runtime.type_info_base(type_info_of(T)) if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { - return s.offsets + return s.offsets[:s.field_count] } return nil } @@ -501,11 +501,11 @@ struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) { ti := runtime.type_info_base(type_info_of(T)) if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { return soa_zip( - name = s.names, - type = s.types, - tag = transmute([]Struct_Tag)s.tags, - offset = s.offsets, - is_using = s.usings, + name = s.names[:s.field_count], + type = s.types[:s.field_count], + tag = ([^]Struct_Tag)(s.tags)[:s.field_count], + offset = s.offsets[:s.field_count], + is_using = s.usings[:s.field_count], ) } return nil @@ -1569,7 +1569,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_ if v.equal != nil { return v.equal(a.data, b.data) } else { - for offset, i in v.offsets { + for offset, i in v.offsets[:v.field_count] { x := rawptr(uintptr(a.data) + offset) y := rawptr(uintptr(b.data) + offset) id := v.types[i].id diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 04dd8a52d..c92d39410 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -115,16 +115,14 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { case Type_Info_Struct: y := b.variant.(Type_Info_Struct) or_return switch { - case len(x.types) != len(y.types), - x.is_packed != y.is_packed, - x.is_raw_union != y.is_raw_union, - x.custom_align != y.custom_align, + case x.field_count != y.field_count, + x.flags != y.flags, x.soa_kind != y.soa_kind, x.soa_base_type != y.soa_base_type, x.soa_len != y.soa_len: return false } - for _, i in x.types { + for i in 0.. bool { case Type_Info_Bit_Field: y := b.variant.(Type_Info_Bit_Field) or_return if !are_types_identical(x.backing_type, y.backing_type) { return false } - if len(x.names) != len(y.names) { return false } - for _, i in x.names { + if x.field_count != y.field_count { return false } + for _, i in x.names[:x.field_count] { if x.names[i] != y.names[i] { return false } @@ -368,13 +366,13 @@ is_tuple :: proc(info: ^Type_Info) -> bool { is_struct :: proc(info: ^Type_Info) -> bool { if info == nil { return false } s, ok := type_info_base(info).variant.(Type_Info_Struct) - return ok && !s.is_raw_union + return ok && .raw_union not_in s.flags } @(require_results) is_raw_union :: proc(info: ^Type_Info) -> bool { if info == nil { return false } s, ok := type_info_base(info).variant.(Type_Info_Struct) - return ok && s.is_raw_union + return ok && .raw_union in s.flags } @(require_results) is_union :: proc(info: ^Type_Info) -> bool { @@ -656,15 +654,16 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) - } io.write_string(w, "struct ", &n) or_return - if info.is_packed { io.write_string(w, "#packed ", &n) or_return } - if info.is_raw_union { io.write_string(w, "#raw_union ", &n) or_return } - if info.custom_align { + if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return } + if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return } + if .no_copy in info.flags { io.write_string(w, "#no_copy ", &n) or_return } + if .align in info.flags { io.write_string(w, "#align(", &n) or_return io.write_i64(w, i64(ti.align), 10, &n) or_return io.write_string(w, ") ", &n) or_return } io.write_byte(w, '{', &n) or_return - for name, i in info.names { + for name, i in info.names[:info.field_count] { if i > 0 { io.write_string(w, ", ", &n) or_return } io.write_string(w, name, &n) or_return io.write_string(w, ": ", &n) or_return @@ -722,7 +721,7 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) - io.write_string(w, "bit_field ", &n) or_return write_type(w, info.backing_type, &n) or_return io.write_string(w, " {", &n) or_return - for name, i in info.names { + for name, i in info.names[:info.field_count] { if i > 0 { io.write_string(w, ", ", &n) or_return } io.write_string(w, name, &n) or_return io.write_string(w, ": ", &n) or_return diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 9cc0552de..5d9caeba1 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -338,6 +338,15 @@ gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, S return addr.addr; } +gb_internal lbValue lb_const_source_code_location_as_global_ptr(lbModule *m, String const &procedure, TokenPos const &pos) { + lbValue loc = lb_const_source_code_location_const(m, procedure, pos); + lbAddr addr = lb_add_global_generated(m, loc.type, loc, nullptr); + lb_make_global_private_const(addr); + return addr.addr; +} + + + gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, Ast *node) { lbValue loc = lb_emit_source_code_location_const(p, node); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 2c4abbb4d..6565717a7 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -421,7 +421,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ } TokenPos pos = t->Named.type_name->token.pos; - lbValue loc = lb_const_source_code_location_const(m, proc_name, pos); + lbValue loc = lb_const_source_code_location_as_global_ptr(m, proc_name, pos); LLVMValueRef vals[4] = { lb_const_string(m, t->Named.type_name->token.string).value, @@ -810,19 +810,18 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ case Type_Struct: { tag_type = t_type_info_struct; - LLVMValueRef vals[13] = {}; + LLVMValueRef vals[11] = {}; { - lbValue is_packed = lb_const_bool(m, t_bool, t->Struct.is_packed); - lbValue is_raw_union = lb_const_bool(m, t_bool, t->Struct.is_raw_union); - lbValue is_no_copy = lb_const_bool(m, t_bool, t->Struct.is_no_copy); - lbValue is_custom_align = lb_const_bool(m, t_bool, t->Struct.custom_align != 0); - vals[5] = is_packed.value; - vals[6] = is_raw_union.value; - vals[7] = is_no_copy.value; - vals[8] = is_custom_align.value; + u8 flags = 0; + if (t->Struct.is_packed) flags |= 1<<0; + if (t->Struct.is_raw_union) flags |= 1<<1; + if (t->Struct.is_no_copy) flags |= 1<<2; + if (t->Struct.custom_align) flags |= 1<<3; + + vals[6] = lb_const_int(m, t_u8, flags).value; if (is_type_comparable(t) && !is_type_simple_compare(t)) { - vals[9] = lb_equal_proc_for_type(m, t).value; + vals[10] = lb_equal_proc_for_type(m, t).value; } @@ -831,11 +830,11 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind)); LLVMValueRef soa_type = get_type_info_ptr(m, t->Struct.soa_elem); - lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count); + lbValue soa_len = lb_const_int(m, t_u16, t->Struct.soa_count); - vals[10] = soa_kind.value; - vals[11] = soa_type; - vals[12] = soa_len.value; + vals[7] = soa_kind.value; + vals[8] = soa_len.value; + vals[9] = soa_type; } } @@ -882,12 +881,13 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ } - lbValue cv = lb_const_int(m, t_int, count); - vals[0] = llvm_const_slice(m, memory_types, cv); - vals[1] = llvm_const_slice(m, memory_names, cv); - vals[2] = llvm_const_slice(m, memory_offsets, cv); - vals[3] = llvm_const_slice(m, memory_usings, cv); - vals[4] = llvm_const_slice(m, memory_tags, cv); + lbValue cv = lb_const_int(m, t_i32, count); + vals[0] = memory_types.value; + vals[1] = memory_names.value; + vals[2] = memory_offsets.value; + vals[3] = memory_usings.value; + vals[4] = memory_tags.value; + vals[5] = cv.value; } for (isize i = 0; i < gb_count_of(vals); i++) { if (vals[i] == nullptr) { @@ -994,7 +994,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ { tag_type = t_type_info_bit_field; - LLVMValueRef vals[6] = {}; + LLVMValueRef vals[7] = {}; vals[0] = get_type_info_ptr(m, t->BitField.backing_type); isize count = t->BitField.fields.count; if (count > 0) { @@ -1035,11 +1035,12 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ } lbValue cv = lb_const_int(m, t_int, count); - vals[1] = llvm_const_slice(m, memory_names, cv); - vals[2] = llvm_const_slice(m, memory_types, cv); - vals[3] = llvm_const_slice(m, memory_bit_sizes, cv); - vals[4] = llvm_const_slice(m, memory_bit_offsets, cv); - vals[5] = llvm_const_slice(m, memory_tags, cv); + vals[1] = memory_names.value; + vals[2] = memory_types.value; + vals[3] = memory_bit_sizes.value; + vals[4] = memory_bit_offsets.value; + vals[5] = memory_tags.value; + vals[6] = cv.value; }