Skip to content

Commit 57b7226

Browse files
Properly print generator interior type sizes
1 parent b0dcadf commit 57b7226

File tree

4 files changed

+219
-100
lines changed

4 files changed

+219
-100
lines changed

compiler/rustc_session/src/code_stats.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub enum SizeKind {
1919
Min,
2020
}
2121

22-
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
22+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
2323
pub struct FieldInfo {
2424
pub name: Symbol,
2525
pub offset: u64,
@@ -114,8 +114,8 @@ impl CodeStats {
114114
let mut max_variant_size = discr_size;
115115

116116
let struct_like = match kind {
117-
DataTypeKind::Struct | DataTypeKind::Closure | DataTypeKind::Generator => true,
118-
DataTypeKind::Enum | DataTypeKind::Union => false,
117+
DataTypeKind::Struct | DataTypeKind::Closure => true,
118+
DataTypeKind::Enum | DataTypeKind::Union | DataTypeKind::Generator => false,
119119
};
120120
for (i, variant_info) in variants.into_iter().enumerate() {
121121
let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info;

compiler/rustc_ty_utils/src/layout.rs

Lines changed: 188 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -814,10 +814,196 @@ fn record_layout_for_printing_outlined<'tcx>(
814814
);
815815
};
816816

817-
let adt_def = match *layout.ty.kind() {
817+
match *layout.ty.kind() {
818818
ty::Adt(ref adt_def, _) => {
819819
debug!("print-type-size t: `{:?}` process adt", layout.ty);
820-
adt_def
820+
let adt_kind = adt_def.adt_kind();
821+
let adt_packed = adt_def.repr().pack.is_some();
822+
823+
let build_variant_info =
824+
|n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
825+
let mut min_size = Size::ZERO;
826+
let field_info: Vec<_> = flds
827+
.iter()
828+
.enumerate()
829+
.map(|(i, &name)| {
830+
let field_layout = layout.field(cx, i);
831+
let offset = layout.fields.offset(i);
832+
min_size = min_size.max(offset + field_layout.size);
833+
FieldInfo {
834+
name,
835+
offset: offset.bytes(),
836+
size: field_layout.size.bytes(),
837+
align: field_layout.align.abi.bytes(),
838+
}
839+
})
840+
.collect();
841+
842+
VariantInfo {
843+
name: n,
844+
kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact },
845+
align: layout.align.abi.bytes(),
846+
size: if min_size.bytes() == 0 {
847+
layout.size.bytes()
848+
} else {
849+
min_size.bytes()
850+
},
851+
fields: field_info,
852+
}
853+
};
854+
855+
match layout.variants {
856+
Variants::Single { index } => {
857+
if !adt_def.variants().is_empty() && layout.fields != FieldsShape::Primitive {
858+
debug!(
859+
"print-type-size `{:#?}` variant {}",
860+
layout,
861+
adt_def.variant(index).name
862+
);
863+
let variant_def = &adt_def.variant(index);
864+
let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
865+
record(
866+
adt_kind.into(),
867+
adt_packed,
868+
None,
869+
vec![build_variant_info(Some(variant_def.name), &fields, layout)],
870+
);
871+
} else {
872+
// (This case arises for *empty* enums; so give it
873+
// zero variants.)
874+
record(adt_kind.into(), adt_packed, None, vec![]);
875+
}
876+
}
877+
878+
Variants::Multiple { tag, ref tag_encoding, .. } => {
879+
debug!(
880+
"print-type-size `{:#?}` adt general variants def {}",
881+
layout.ty,
882+
adt_def.variants().len()
883+
);
884+
let variant_infos: Vec<_> = adt_def
885+
.variants()
886+
.iter_enumerated()
887+
.map(|(i, variant_def)| {
888+
let fields: Vec<_> =
889+
variant_def.fields.iter().map(|f| f.name).collect();
890+
build_variant_info(
891+
Some(variant_def.name),
892+
&fields,
893+
layout.for_variant(cx, i),
894+
)
895+
})
896+
.collect();
897+
record(
898+
adt_kind.into(),
899+
adt_packed,
900+
match tag_encoding {
901+
TagEncoding::Direct => Some(tag.size(cx)),
902+
_ => None,
903+
},
904+
variant_infos,
905+
);
906+
}
907+
}
908+
}
909+
910+
ty::Generator(def_id, substs, _) => {
911+
debug!("print-type-size t: `{:?}` record generator", layout.ty);
912+
// Generators always have a begin/poisoned/end state with additional suspend points
913+
match layout.variants {
914+
Variants::Multiple { tag, ref tag_encoding, .. } => {
915+
let (generator, state_specific_names) =
916+
cx.tcx.generator_layout_and_saved_local_names(def_id);
917+
let upvar_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
918+
919+
let mut upvars_size = Size::ZERO;
920+
let upvar_fields: Vec<_> = substs
921+
.as_generator()
922+
.upvar_tys()
923+
.zip(upvar_names)
924+
.enumerate()
925+
.map(|(field_idx, (_, name))| {
926+
let field_layout = layout.field(cx, field_idx);
927+
let offset = layout.fields.offset(field_idx);
928+
upvars_size = upvars_size.max(offset + field_layout.size);
929+
FieldInfo {
930+
name: Symbol::intern(&name),
931+
offset: offset.bytes(),
932+
size: field_layout.size.bytes(),
933+
align: field_layout.align.abi.bytes(),
934+
}
935+
})
936+
.collect();
937+
938+
let variant_infos: Vec<_> = generator
939+
.variant_fields
940+
.iter_enumerated()
941+
.map(|(variant_idx, variant_def)| {
942+
let variant_layout = layout.for_variant(cx, variant_idx);
943+
let mut variant_size = Size::ZERO;
944+
let fields = variant_def
945+
.iter()
946+
.enumerate()
947+
.map(|(field_idx, local)| {
948+
let field_layout = variant_layout.field(cx, field_idx);
949+
let offset = variant_layout.fields.offset(field_idx);
950+
// The struct is as large as the last field's end
951+
variant_size = variant_size.max(offset + field_layout.size);
952+
FieldInfo {
953+
name: state_specific_names
954+
.get(*local)
955+
.copied()
956+
.flatten()
957+
.unwrap_or(Symbol::intern(&format!(
958+
".generator_field{}",
959+
local.as_usize()
960+
))),
961+
offset: offset.bytes(),
962+
size: field_layout.size.bytes(),
963+
align: field_layout.align.abi.bytes(),
964+
}
965+
})
966+
.chain(upvar_fields.iter().copied())
967+
.collect();
968+
969+
// If the variant has no state-specific fields, then it's the size of the upvars.
970+
if variant_size == Size::ZERO {
971+
variant_size = upvars_size;
972+
}
973+
// We need to add the discriminant size back into min_size, since it is subtracted
974+
// later during printing.
975+
variant_size += match tag_encoding {
976+
TagEncoding::Direct => tag.size(cx),
977+
_ => Size::ZERO,
978+
};
979+
980+
VariantInfo {
981+
name: Some(Symbol::intern(&ty::GeneratorSubsts::variant_name(
982+
variant_idx,
983+
))),
984+
kind: SizeKind::Exact,
985+
size: variant_size.bytes(),
986+
align: variant_layout.align.abi.bytes(),
987+
fields,
988+
}
989+
})
990+
.collect();
991+
record(
992+
DataTypeKind::Generator,
993+
false,
994+
match tag_encoding {
995+
TagEncoding::Direct => Some(tag.size(cx)),
996+
_ => None,
997+
},
998+
variant_infos,
999+
);
1000+
}
1001+
_ => {
1002+
// This should never happen, but I would rather not panic.
1003+
record(DataTypeKind::Generator, false, None, vec![]);
1004+
return;
1005+
}
1006+
}
8211007
}
8221008

8231009
ty::Closure(..) => {
@@ -826,93 +1012,9 @@ fn record_layout_for_printing_outlined<'tcx>(
8261012
return;
8271013
}
8281014

829-
ty::Generator(..) => {
830-
debug!("print-type-size t: `{:?}` record generator", layout.ty);
831-
record(DataTypeKind::Generator, false, None, vec![]);
832-
return;
833-
}
834-
8351015
_ => {
8361016
debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty);
8371017
return;
8381018
}
8391019
};
840-
841-
let adt_kind = adt_def.adt_kind();
842-
let adt_packed = adt_def.repr().pack.is_some();
843-
844-
let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
845-
let mut min_size = Size::ZERO;
846-
let field_info: Vec<_> = flds
847-
.iter()
848-
.enumerate()
849-
.map(|(i, &name)| {
850-
let field_layout = layout.field(cx, i);
851-
let offset = layout.fields.offset(i);
852-
let field_end = offset + field_layout.size;
853-
if min_size < field_end {
854-
min_size = field_end;
855-
}
856-
FieldInfo {
857-
name,
858-
offset: offset.bytes(),
859-
size: field_layout.size.bytes(),
860-
align: field_layout.align.abi.bytes(),
861-
}
862-
})
863-
.collect();
864-
865-
VariantInfo {
866-
name: n,
867-
kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact },
868-
align: layout.align.abi.bytes(),
869-
size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() },
870-
fields: field_info,
871-
}
872-
};
873-
874-
match layout.variants {
875-
Variants::Single { index } => {
876-
if !adt_def.variants().is_empty() && layout.fields != FieldsShape::Primitive {
877-
debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variant(index).name);
878-
let variant_def = &adt_def.variant(index);
879-
let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
880-
record(
881-
adt_kind.into(),
882-
adt_packed,
883-
None,
884-
vec![build_variant_info(Some(variant_def.name), &fields, layout)],
885-
);
886-
} else {
887-
// (This case arises for *empty* enums; so give it
888-
// zero variants.)
889-
record(adt_kind.into(), adt_packed, None, vec![]);
890-
}
891-
}
892-
893-
Variants::Multiple { tag, ref tag_encoding, .. } => {
894-
debug!(
895-
"print-type-size `{:#?}` adt general variants def {}",
896-
layout.ty,
897-
adt_def.variants().len()
898-
);
899-
let variant_infos: Vec<_> = adt_def
900-
.variants()
901-
.iter_enumerated()
902-
.map(|(i, variant_def)| {
903-
let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
904-
build_variant_info(Some(variant_def.name), &fields, layout.for_variant(cx, i))
905-
})
906-
.collect();
907-
record(
908-
adt_kind.into(),
909-
adt_packed,
910-
match tag_encoding {
911-
TagEncoding::Direct => Some(tag.size(cx)),
912-
_ => None,
913-
},
914-
variant_infos,
915-
);
916-
}
917-
}
9181020
}

src/test/ui/print_type_sizes/async.stdout

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
1-
print-type-size type: `[static generator@$DIR/async.rs:10:32: 13:2]`: 16386 bytes, alignment: 1 bytes
2-
print-type-size end padding: 16386 bytes
3-
print-type-size type: `std::future::from_generator::GenFuture<[static generator@$DIR/async.rs:10:32: 13:2]>`: 16386 bytes, alignment: 1 bytes
4-
print-type-size field `.0`: 16386 bytes
1+
print-type-size type: `[async fn body@$DIR/async.rs:10:32: 13:2]`: 16386 bytes, alignment: 1 bytes
2+
print-type-size discriminant: 1 bytes
3+
print-type-size variant `Suspend0`: 16385 bytes
4+
print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
5+
print-type-size field `.arg`: 8192 bytes
6+
print-type-size field `.__awaitee`: 1 bytes
7+
print-type-size variant `Unresumed`: 8192 bytes
8+
print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
9+
print-type-size variant `Returned`: 8192 bytes
10+
print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
11+
print-type-size variant `Panicked`: 8192 bytes
12+
print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
513
print-type-size type: `std::mem::ManuallyDrop<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes
614
print-type-size field `.value`: 8192 bytes
715
print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes
816
print-type-size variant `MaybeUninit`: 8192 bytes
917
print-type-size field `.uninit`: 0 bytes
1018
print-type-size field `.value`: 8192 bytes
11-
print-type-size type: `[static generator@$DIR/async.rs:8:17: 8:19]`: 1 bytes, alignment: 1 bytes
12-
print-type-size end padding: 1 bytes
13-
print-type-size type: `std::future::from_generator::GenFuture<[static generator@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
14-
print-type-size field `.0`: 1 bytes
15-
print-type-size type: `std::mem::ManuallyDrop<std::future::from_generator::GenFuture<[static generator@$DIR/async.rs:8:17: 8:19]>>`: 1 bytes, alignment: 1 bytes
19+
print-type-size type: `[async fn body@$DIR/async.rs:8:17: 8:19]`: 1 bytes, alignment: 1 bytes
20+
print-type-size discriminant: 1 bytes
21+
print-type-size variant `Unresumed`: 0 bytes
22+
print-type-size variant `Returned`: 0 bytes
23+
print-type-size variant `Panicked`: 0 bytes
24+
print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
1625
print-type-size field `.value`: 1 bytes
17-
print-type-size type: `std::mem::MaybeUninit<std::future::from_generator::GenFuture<[static generator@$DIR/async.rs:8:17: 8:19]>>`: 1 bytes, alignment: 1 bytes
26+
print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
1827
print-type-size variant `MaybeUninit`: 1 bytes
1928
print-type-size field `.uninit`: 0 bytes
2029
print-type-size field `.value`: 1 bytes
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,10 @@
11
print-type-size type: `[generator@$DIR/generator.rs:10:5: 10:14]`: 8193 bytes, alignment: 1 bytes
2-
print-type-size end padding: 8193 bytes
2+
print-type-size discriminant: 1 bytes
3+
print-type-size variant `Unresumed`: 8192 bytes
4+
print-type-size field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
5+
print-type-size variant `Returned`: 8192 bytes
6+
print-type-size field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
7+
print-type-size variant `Panicked`: 8192 bytes
8+
print-type-size field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
9+
print-type-size variant `Suspend0`: 8192 bytes
10+
print-type-size field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes

0 commit comments

Comments
 (0)