1 use rustc_data_structures
::fx
::FxHashSet
;
2 use rustc_data_structures
::sync
::Lock
;
3 use rustc_target
::abi
::{Align, Size}
;
4 use std
::cmp
::{self, Ordering}
;
6 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
7 pub struct VariantInfo
{
8 pub name
: Option
<String
>,
12 pub fields
: Vec
<FieldInfo
>,
15 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
21 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
22 pub struct FieldInfo
{
29 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
30 pub enum DataTypeKind
{
37 #[derive(PartialEq, Eq, Hash, Debug)]
38 pub struct TypeSizeInfo
{
39 pub kind
: DataTypeKind
,
40 pub type_description
: String
,
42 pub overall_size
: u64,
44 pub opt_discr_size
: Option
<u64>,
45 pub variants
: Vec
<VariantInfo
>,
49 pub struct CodeStats
{
50 type_sizes
: Lock
<FxHashSet
<TypeSizeInfo
>>,
54 pub fn record_type_size
<S
: ToString
>(
61 opt_discr_size
: Option
<Size
>,
62 mut variants
: Vec
<VariantInfo
>,
64 // Sort variants so the largest ones are shown first. A stable sort is
65 // used here so that source code order is preserved for all variants
66 // that have the same size.
67 variants
.sort_by(|info1
, info2
| info2
.size
.cmp(&info1
.size
));
68 let info
= TypeSizeInfo
{
70 type_description
: type_desc
.to_string(),
72 overall_size
: overall_size
.bytes(),
74 opt_discr_size
: opt_discr_size
.map(|s
| s
.bytes()),
77 self.type_sizes
.borrow_mut().insert(info
);
80 pub fn print_type_sizes(&self) {
81 let type_sizes
= self.type_sizes
.borrow();
82 let mut sorted
: Vec
<_
> = type_sizes
.iter().collect();
84 // Primary sort: large-to-small.
85 // Secondary sort: description (dictionary order)
86 sorted
.sort_by(|info1
, info2
| {
87 // (reversing cmp order to get large-to-small ordering)
88 match info2
.overall_size
.cmp(&info1
.overall_size
) {
89 Ordering
::Equal
=> info1
.type_description
.cmp(&info2
.type_description
),
96 "print-type-size type: `{}`: {} bytes, alignment: {} bytes",
97 info
.type_description
, info
.overall_size
, info
.align
101 let discr_size
= if let Some(discr_size
) = info
.opt_discr_size
{
102 println
!("print-type-size {}discriminant: {} bytes", indent
, discr_size
);
108 // We start this at discr_size (rather than 0) because
109 // things like C-enums do not have variants but we still
110 // want the max_variant_size at the end of the loop below
111 // to reflect the presence of the discriminant.
112 let mut max_variant_size
= discr_size
;
114 let struct_like
= match info
.kind
{
115 DataTypeKind
::Struct
| DataTypeKind
::Closure
=> true,
116 DataTypeKind
::Enum
| DataTypeKind
::Union
=> false,
118 for (i
, variant_info
) in info
.variants
.iter().enumerate() {
119 let VariantInfo { ref name, kind: _, align: _, size, ref fields }
= *variant_info
;
120 let indent
= if !struct_like
{
121 let name
= match name
.as_ref() {
122 Some(name
) => name
.to_owned(),
123 None
=> i
.to_string(),
126 "print-type-size {}variant `{}`: {} bytes",
136 max_variant_size
= cmp
::max(max_variant_size
, size
);
138 let mut min_offset
= discr_size
;
140 // We want to print fields by increasing offset. We also want
141 // zero-sized fields before non-zero-sized fields, otherwise
142 // the loop below goes wrong; hence the `f.size` in the sort
144 let mut fields
= fields
.clone();
145 fields
.sort_by_key(|f
| (f
.offset
, f
.size
));
147 for field
in fields
.iter() {
148 let FieldInfo { ref name, offset, size, align }
= *field
;
150 if offset
> min_offset
{
151 let pad
= offset
- min_offset
;
152 println
!("print-type-size {}padding: {} bytes", indent
, pad
);
155 if offset
< min_offset
{
156 // If this happens it's probably a union.
158 "print-type-size {}field `.{}`: {} bytes, \
160 alignment: {} bytes",
161 indent
, name
, size
, offset
, align
163 } else if info
.packed
|| offset
== min_offset
{
164 println
!("print-type-size {}field `.{}`: {} bytes", indent
, name
, size
);
166 // Include field alignment in output only if it caused padding injection
168 "print-type-size {}field `.{}`: {} bytes, \
169 alignment: {} bytes",
170 indent
, name
, size
, align
174 min_offset
= offset
+ size
;
179 max_variant_size
<= info
.overall_size
,
180 "max_variant_size {} !<= {} overall_size",
184 if max_variant_size
< info
.overall_size
{
186 "print-type-size {}end padding: {} bytes",
188 info
.overall_size
- max_variant_size