1use std::cmp;
2
3use rustc_abi::{Align, Size};
4use rustc_data_structures::fx::FxHashSet;
5use rustc_data_structures::sync::Lock;
6use rustc_span::Symbol;
7
8#[derive(#[automatically_derived]
impl ::core::clone::Clone for VariantInfo {
#[inline]
fn clone(&self) -> VariantInfo {
VariantInfo {
name: ::core::clone::Clone::clone(&self.name),
kind: ::core::clone::Clone::clone(&self.kind),
size: ::core::clone::Clone::clone(&self.size),
align: ::core::clone::Clone::clone(&self.align),
fields: ::core::clone::Clone::clone(&self.fields),
}
}
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for VariantInfo {
#[inline]
fn eq(&self, other: &VariantInfo) -> bool {
self.size == other.size && self.align == other.align &&
self.name == other.name && self.kind == other.kind &&
self.fields == other.fields
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for VariantInfo {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<Option<Symbol>>;
let _: ::core::cmp::AssertParamIsEq<SizeKind>;
let _: ::core::cmp::AssertParamIsEq<u64>;
let _: ::core::cmp::AssertParamIsEq<Vec<FieldInfo>>;
}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for VariantInfo {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.name, state);
::core::hash::Hash::hash(&self.kind, state);
::core::hash::Hash::hash(&self.size, state);
::core::hash::Hash::hash(&self.align, state);
::core::hash::Hash::hash(&self.fields, state)
}
}Hash, #[automatically_derived]
impl ::core::fmt::Debug for VariantInfo {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field5_finish(f, "VariantInfo",
"name", &self.name, "kind", &self.kind, "size", &self.size,
"align", &self.align, "fields", &&self.fields)
}
}Debug)]
9pub struct VariantInfo {
10 pub name: Option<Symbol>,
11 pub kind: SizeKind,
12 pub size: u64,
13 pub align: u64,
14 pub fields: Vec<FieldInfo>,
15}
16
17#[derive(#[automatically_derived]
impl ::core::marker::Copy for SizeKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for SizeKind {
#[inline]
fn clone(&self) -> SizeKind { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for SizeKind {
#[inline]
fn eq(&self, other: &SizeKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SizeKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for SizeKind {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
let __self_discr = ::core::intrinsics::discriminant_value(self);
::core::hash::Hash::hash(&__self_discr, state)
}
}Hash, #[automatically_derived]
impl ::core::fmt::Debug for SizeKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
SizeKind::Exact => "Exact",
SizeKind::Min => "Min",
})
}
}Debug)]
18pub enum SizeKind {
19 Exact,
20 Min,
21}
22
23#[derive(#[automatically_derived]
impl ::core::marker::Copy for FieldKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for FieldKind {
#[inline]
fn clone(&self) -> FieldKind { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for FieldKind {
#[inline]
fn eq(&self, other: &FieldKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for FieldKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for FieldKind {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
let __self_discr = ::core::intrinsics::discriminant_value(self);
::core::hash::Hash::hash(&__self_discr, state)
}
}Hash, #[automatically_derived]
impl ::core::fmt::Debug for FieldKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
FieldKind::AdtField => "AdtField",
FieldKind::Upvar => "Upvar",
FieldKind::CoroutineLocal => "CoroutineLocal",
})
}
}Debug)]
24pub enum FieldKind {
25 AdtField,
26 Upvar,
27 CoroutineLocal,
28}
29
30impl std::fmt::Display for FieldKind {
31 fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 match self {
33 FieldKind::AdtField => w.write_fmt(format_args!("field"))write!(w, "field"),
34 FieldKind::Upvar => w.write_fmt(format_args!("upvar"))write!(w, "upvar"),
35 FieldKind::CoroutineLocal => w.write_fmt(format_args!("local"))write!(w, "local"),
36 }
37 }
38}
39
40#[derive(#[automatically_derived]
impl ::core::marker::Copy for FieldInfo { }Copy, #[automatically_derived]
impl ::core::clone::Clone for FieldInfo {
#[inline]
fn clone(&self) -> FieldInfo {
let _: ::core::clone::AssertParamIsClone<FieldKind>;
let _: ::core::clone::AssertParamIsClone<Symbol>;
let _: ::core::clone::AssertParamIsClone<u64>;
let _: ::core::clone::AssertParamIsClone<Option<Symbol>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for FieldInfo {
#[inline]
fn eq(&self, other: &FieldInfo) -> bool {
self.offset == other.offset && self.size == other.size &&
self.align == other.align && self.kind == other.kind &&
self.name == other.name && self.type_name == other.type_name
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for FieldInfo {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<FieldKind>;
let _: ::core::cmp::AssertParamIsEq<Symbol>;
let _: ::core::cmp::AssertParamIsEq<u64>;
let _: ::core::cmp::AssertParamIsEq<Option<Symbol>>;
}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for FieldInfo {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.kind, state);
::core::hash::Hash::hash(&self.name, state);
::core::hash::Hash::hash(&self.offset, state);
::core::hash::Hash::hash(&self.size, state);
::core::hash::Hash::hash(&self.align, state);
::core::hash::Hash::hash(&self.type_name, state)
}
}Hash, #[automatically_derived]
impl ::core::fmt::Debug for FieldInfo {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["kind", "name", "offset", "size", "align", "type_name"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.kind, &self.name, &self.offset, &self.size, &self.align,
&&self.type_name];
::core::fmt::Formatter::debug_struct_fields_finish(f, "FieldInfo",
names, values)
}
}Debug)]
41pub struct FieldInfo {
42 pub kind: FieldKind,
43 pub name: Symbol,
44 pub offset: u64,
45 pub size: u64,
46 pub align: u64,
47 pub type_name: Option<Symbol>,
51}
52
53#[derive(#[automatically_derived]
impl ::core::marker::Copy for DataTypeKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for DataTypeKind {
#[inline]
fn clone(&self) -> DataTypeKind { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for DataTypeKind {
#[inline]
fn eq(&self, other: &DataTypeKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for DataTypeKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for DataTypeKind {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
let __self_discr = ::core::intrinsics::discriminant_value(self);
::core::hash::Hash::hash(&__self_discr, state)
}
}Hash, #[automatically_derived]
impl ::core::fmt::Debug for DataTypeKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
DataTypeKind::Struct => "Struct",
DataTypeKind::Union => "Union",
DataTypeKind::Enum => "Enum",
DataTypeKind::Closure => "Closure",
DataTypeKind::Coroutine => "Coroutine",
})
}
}Debug)]
54pub enum DataTypeKind {
55 Struct,
56 Union,
57 Enum,
58 Closure,
59 Coroutine,
60}
61
62#[derive(#[automatically_derived]
impl ::core::cmp::PartialEq for TypeSizeInfo {
#[inline]
fn eq(&self, other: &TypeSizeInfo) -> bool {
self.align == other.align && self.overall_size == other.overall_size
&& self.packed == other.packed && self.kind == other.kind &&
self.type_description == other.type_description &&
self.opt_discr_size == other.opt_discr_size &&
self.variants == other.variants
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for TypeSizeInfo {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<DataTypeKind>;
let _: ::core::cmp::AssertParamIsEq<String>;
let _: ::core::cmp::AssertParamIsEq<u64>;
let _: ::core::cmp::AssertParamIsEq<bool>;
let _: ::core::cmp::AssertParamIsEq<Option<u64>>;
let _: ::core::cmp::AssertParamIsEq<Vec<VariantInfo>>;
}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for TypeSizeInfo {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.kind, state);
::core::hash::Hash::hash(&self.type_description, state);
::core::hash::Hash::hash(&self.align, state);
::core::hash::Hash::hash(&self.overall_size, state);
::core::hash::Hash::hash(&self.packed, state);
::core::hash::Hash::hash(&self.opt_discr_size, state);
::core::hash::Hash::hash(&self.variants, state)
}
}Hash, #[automatically_derived]
impl ::core::fmt::Debug for TypeSizeInfo {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["kind", "type_description", "align", "overall_size", "packed",
"opt_discr_size", "variants"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.kind, &self.type_description, &self.align,
&self.overall_size, &self.packed, &self.opt_discr_size,
&&self.variants];
::core::fmt::Formatter::debug_struct_fields_finish(f, "TypeSizeInfo",
names, values)
}
}Debug)]
63pub struct TypeSizeInfo {
64 pub kind: DataTypeKind,
65 pub type_description: String,
66 pub align: u64,
67 pub overall_size: u64,
68 pub packed: bool,
69 pub opt_discr_size: Option<u64>,
70 pub variants: Vec<VariantInfo>,
71}
72
73#[derive(#[automatically_derived]
impl ::core::default::Default for CodeStats {
#[inline]
fn default() -> CodeStats {
CodeStats { type_sizes: ::core::default::Default::default() }
}
}Default)]
74pub struct CodeStats {
75 pub type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
78}
79
80impl CodeStats {
81 pub fn record_type_size<S: ToString>(
82 &self,
83 kind: DataTypeKind,
84 type_desc: S,
85 align: Align,
86 overall_size: Size,
87 packed: bool,
88 opt_discr_size: Option<Size>,
89 mut variants: Vec<VariantInfo>,
90 ) {
91 if kind != DataTypeKind::Coroutine {
97 variants.sort_by_key(|info| cmp::Reverse(info.size));
98 }
99 let info = TypeSizeInfo {
100 kind,
101 type_description: type_desc.to_string(),
102 align: align.bytes(),
103 overall_size: overall_size.bytes(),
104 packed,
105 opt_discr_size: opt_discr_size.map(|s| s.bytes()),
106 variants,
107 };
108 self.type_sizes.borrow_mut().insert(info);
109 }
110
111 pub fn print_type_sizes(&self) {
112 let type_sizes = self.type_sizes.borrow();
113 #[allow(rustc::potential_query_instability)]
115 let mut sorted: Vec<_> = type_sizes.iter().collect();
116
117 sorted.sort_by_key(|info| (cmp::Reverse(info.overall_size), &info.type_description));
120
121 for info in sorted {
122 let TypeSizeInfo { type_description, overall_size, align, kind, variants, .. } = info;
123 {
::std::io::_print(format_args!("print-type-size type: `{0}`: {1} bytes, alignment: {2} bytes\n",
type_description, overall_size, align));
};println!(
124 "print-type-size type: `{type_description}`: {overall_size} bytes, alignment: {align} bytes"
125 );
126 let indent = " ";
127
128 let discr_size = if let Some(discr_size) = info.opt_discr_size {
129 {
::std::io::_print(format_args!("print-type-size {0}discriminant: {1} bytes\n",
indent, discr_size));
};println!("print-type-size {indent}discriminant: {discr_size} bytes");
130 discr_size
131 } else {
132 0
133 };
134
135 let mut max_variant_size = discr_size;
140
141 let struct_like = match kind {
142 DataTypeKind::Struct | DataTypeKind::Closure => true,
143 DataTypeKind::Enum | DataTypeKind::Union | DataTypeKind::Coroutine => false,
144 };
145 for (i, variant_info) in variants.into_iter().enumerate() {
146 let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info;
147 let indent = if !struct_like {
148 let name = match name.as_ref() {
149 Some(name) => name.to_string(),
150 None => i.to_string(),
151 };
152 {
::std::io::_print(format_args!("print-type-size {1}variant `{2}`: {0} bytes\n",
size - discr_size, indent, name));
};println!(
153 "print-type-size {indent}variant `{name}`: {diff} bytes",
154 diff = size - discr_size
155 );
156 " "
157 } else {
158 if !(i < 1) { ::core::panicking::panic("assertion failed: i < 1") };assert!(i < 1);
159 " "
160 };
161 max_variant_size = cmp::max(max_variant_size, size);
162
163 let mut min_offset = discr_size;
164
165 let mut fields = fields.clone();
170 fields.sort_by_key(|f| (f.offset, f.size));
171
172 for field in fields {
173 let FieldInfo { kind, ref name, offset, size, align, type_name } = field;
174
175 if offset > min_offset {
176 let pad = offset - min_offset;
177 {
::std::io::_print(format_args!("print-type-size {0}padding: {1} bytes\n",
indent, pad));
};println!("print-type-size {indent}padding: {pad} bytes");
178 }
179
180 if offset < min_offset {
181 {
::std::io::_print(format_args!("print-type-size {0}{1} `.{2}`: {3} bytes, offset: {4} bytes, alignment: {5} bytes",
indent, kind, name, size, offset, align));
};print!(
183 "print-type-size {indent}{kind} `.{name}`: {size} bytes, \
184 offset: {offset} bytes, \
185 alignment: {align} bytes"
186 );
187 } else if info.packed || offset == min_offset {
188 {
::std::io::_print(format_args!("print-type-size {0}{1} `.{2}`: {3} bytes",
indent, kind, name, size));
};print!("print-type-size {indent}{kind} `.{name}`: {size} bytes");
189 } else {
190 {
::std::io::_print(format_args!("print-type-size {0}{1} `.{2}`: {3} bytes, alignment: {4} bytes",
indent, kind, name, size, align));
};print!(
192 "print-type-size {indent}{kind} `.{name}`: {size} bytes, \
193 alignment: {align} bytes"
194 );
195 }
196
197 if let Some(type_name) = type_name {
198 { ::std::io::_print(format_args!(", type: {0}\n", type_name)); };println!(", type: {type_name}");
199 } else {
200 { ::std::io::_print(format_args!("\n")); };println!();
201 }
202
203 min_offset = offset + size;
204 }
205 }
206
207 match overall_size.checked_sub(max_variant_size) {
208 None => {
::core::panicking::panic_fmt(format_args!("max_variant_size {0} > {1} overall_size",
max_variant_size, overall_size));
}panic!("max_variant_size {max_variant_size} > {overall_size} overall_size"),
209 Some(diff @ 1..) => {
::std::io::_print(format_args!("print-type-size {0}end padding: {1} bytes\n",
indent, diff));
}println!("print-type-size {indent}end padding: {diff} bytes"),
210 Some(0) => {}
211 }
212 }
213 }
214}