Browse Source

Reduce the size of `runtime.Type_Info`

gingerBill 1 year ago
parent
commit
399c3ab067

+ 30 - 20
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_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 {
-	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,
+	// Slice these with `field_count`
+	types:   [^]^Type_Info,
+	names:   [^]string,
+	offsets: [^]uintptr,
+	usings:  [^]bool,
+	tags:    [^]string,
 
-	equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set
+	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 {

+ 6 - 5
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(": ")

+ 3 - 3
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

+ 1 - 1
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)
 		}
 

+ 1 - 1
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"))

+ 1 - 1
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
 		}
 	

+ 8 - 8
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

+ 13 - 13
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

+ 13 - 14
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..<x.field_count {
 			xn, yn := x.names[i], y.names[i]
 			xt, yt := x.types[i], y.types[i]
 			xl, yl := x.tags[i],  y.tags[i]
@@ -179,8 +177,8 @@ are_types_identical :: proc(a, b: ^Type_Info) -> 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

+ 9 - 0
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);

+ 28 - 27
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;
 				}