Skip to content

Commit

Permalink
Rollup merge of rust-lang#122922 - kpreid:print-async, r=compiler-errors
Browse files Browse the repository at this point in the history
-Zprint-type-sizes: print the types of awaitees and unnamed coroutine locals.

This should assist comprehending the size of coroutines. In particular, whenever a future is suspended while awaiting another future, the latter is given the special name `__awaitee`, and now the type of the awaited future will be printed, allowing identifying caller/callee — er, I mean, poller/pollee — relationships.

It would be possible to include the type name in more cases, but I thought that that might be overly verbose (`print-type-sizes` is already a lot of text) and ordinary named fields or variables are easier for readers to discover the types of.

This change will also synergize with my other PR rust-lang#122923 which changes type printing to print the path of the `async fn` instead of the span.

Implementation note: I'm not sure if `Symbol::intern` is appropriate for this application, but it was the obvious way to not have to remove the `Copy` implementation from `FieldInfo`, or add a `'tcx` lifetime, while avoiding keeping a lot of possibly redundant strings in memory. I don't know what the proper tradeoff to make here is (though presumably it is not too important for a `-Z` debugging option).
  • Loading branch information
workingjubilee committed Mar 23, 2024
2 parents fa762ea + 44d185b commit 6f506a6
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 16 deletions.
18 changes: 14 additions & 4 deletions compiler/rustc_session/src/code_stats.rs
Expand Up @@ -44,6 +44,10 @@ pub struct FieldInfo {
pub offset: u64,
pub size: u64,
pub align: u64,
/// Name of the type of this field.
/// Present only if the creator thought that this would be important for identifying the field,
/// typically because the field name is uninformative.
pub type_name: Option<Symbol>,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
Expand Down Expand Up @@ -192,7 +196,7 @@ impl CodeStats {
fields.sort_by_key(|f| (f.offset, f.size));

for field in fields {
let FieldInfo { kind, ref name, offset, size, align } = field;
let FieldInfo { kind, ref name, offset, size, align, type_name } = field;

if offset > min_offset {
let pad = offset - min_offset;
Expand All @@ -201,21 +205,27 @@ impl CodeStats {

if offset < min_offset {
// If this happens it's probably a union.
println!(
print!(
"print-type-size {indent}{kind} `.{name}`: {size} bytes, \
offset: {offset} bytes, \
alignment: {align} bytes"
);
} else if info.packed || offset == min_offset {
println!("print-type-size {indent}{kind} `.{name}`: {size} bytes");
print!("print-type-size {indent}{kind} `.{name}`: {size} bytes");
} else {
// Include field alignment in output only if it caused padding injection
println!(
print!(
"print-type-size {indent}{kind} `.{name}`: {size} bytes, \
alignment: {align} bytes"
);
}

if let Some(type_name) = type_name {
println!(", type: {type_name}");
} else {
println!();
}

min_offset = offset + size;
}
}
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_ty_utils/src/layout.rs
Expand Up @@ -10,6 +10,7 @@ use rustc_middle::ty::layout::{
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
use rustc_span::sym;
use rustc_span::symbol::Symbol;
use rustc_target::abi::*;

Expand Down Expand Up @@ -1007,6 +1008,7 @@ fn variant_info_for_adt<'tcx>(
offset: offset.bytes(),
size: field_layout.size.bytes(),
align: field_layout.align.abi.bytes(),
type_name: None,
}
})
.collect();
Expand Down Expand Up @@ -1090,6 +1092,7 @@ fn variant_info_for_coroutine<'tcx>(
offset: offset.bytes(),
size: field_layout.size.bytes(),
align: field_layout.align.abi.bytes(),
type_name: None,
}
})
.collect();
Expand All @@ -1104,19 +1107,24 @@ fn variant_info_for_coroutine<'tcx>(
.iter()
.enumerate()
.map(|(field_idx, local)| {
let field_name = coroutine.field_names[*local];
let field_layout = variant_layout.field(cx, field_idx);
let offset = variant_layout.fields.offset(field_idx);
// The struct is as large as the last field's end
variant_size = variant_size.max(offset + field_layout.size);
FieldInfo {
kind: FieldKind::CoroutineLocal,
name: coroutine.field_names[*local].unwrap_or(Symbol::intern(&format!(
name: field_name.unwrap_or(Symbol::intern(&format!(
".coroutine_field{}",
local.as_usize()
))),
offset: offset.bytes(),
size: field_layout.size.bytes(),
align: field_layout.align.abi.bytes(),
// Include the type name if there is no field name, or if the name is the
// __awaitee placeholder symbol which means a child future being `.await`ed.
type_name: (field_name.is_none() || field_name == Some(sym::__awaitee))
.then(|| Symbol::intern(&field_layout.ty.to_string())),
}
})
.chain(upvar_fields.iter().copied())
Expand Down
14 changes: 7 additions & 7 deletions tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
Expand Up @@ -2,7 +2,7 @@ print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2}`:
print-type-size discriminant: 1 bytes
print-type-size variant `Unresumed`: 0 bytes
print-type-size variant `Suspend0`: 3077 bytes
print-type-size local `.__awaitee`: 3077 bytes
print-type-size local `.__awaitee`: 3077 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}
print-type-size variant `Returned`: 0 bytes
print-type-size variant `Panicked`: 0 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}>`: 3077 bytes, alignment: 1 bytes
Expand All @@ -19,19 +19,19 @@ print-type-size variant `Suspend0`: 2052 bytes
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
print-type-size padding: 1 bytes
print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes
print-type-size local `..coroutine_field4`: 1 bytes
print-type-size local `.__awaitee`: 1 bytes
print-type-size local `..coroutine_field4`: 1 bytes, type: bool
print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}
print-type-size variant `Suspend1`: 3076 bytes
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
print-type-size padding: 1026 bytes
print-type-size local `..coroutine_field4`: 1 bytes, alignment: 1 bytes
print-type-size local `.__awaitee`: 1025 bytes
print-type-size local `..coroutine_field4`: 1 bytes, alignment: 1 bytes, type: bool
print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37}
print-type-size variant `Suspend2`: 2052 bytes
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
print-type-size padding: 1 bytes
print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes
print-type-size local `..coroutine_field4`: 1 bytes
print-type-size local `.__awaitee`: 1 bytes
print-type-size local `..coroutine_field4`: 1 bytes, type: bool
print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}
print-type-size variant `Returned`: 1025 bytes
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
print-type-size variant `Panicked`: 1025 bytes
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/async-await/future-sizes/large-arg.stdout
Expand Up @@ -2,7 +2,7 @@ print-type-size type: `{async fn body@$DIR/large-arg.rs:6:21: 8:2}`: 3076 bytes,
print-type-size discriminant: 1 bytes
print-type-size variant `Unresumed`: 0 bytes
print-type-size variant `Suspend0`: 3075 bytes
print-type-size local `.__awaitee`: 3075 bytes
print-type-size local `.__awaitee`: 3075 bytes, type: {async fn body@$DIR/large-arg.rs:10:30: 12:2}
print-type-size variant `Returned`: 0 bytes
print-type-size variant `Panicked`: 0 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/large-arg.rs:10:30: 12:2}>`: 3075 bytes, alignment: 1 bytes
Expand All @@ -17,7 +17,7 @@ print-type-size variant `Unresumed`: 1024 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size variant `Suspend0`: 3074 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size local `.__awaitee`: 2050 bytes
print-type-size local `.__awaitee`: 2050 bytes, type: {async fn body@$DIR/large-arg.rs:13:26: 15:2}
print-type-size variant `Returned`: 1024 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size variant `Panicked`: 1024 bytes
Expand All @@ -34,7 +34,7 @@ print-type-size variant `Unresumed`: 1024 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size variant `Suspend0`: 2049 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size local `.__awaitee`: 1025 bytes
print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/large-arg.rs:16:26: 18:2}
print-type-size variant `Returned`: 1024 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size variant `Panicked`: 1024 bytes
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/print_type_sizes/async.stdout
Expand Up @@ -5,7 +5,7 @@ print-type-size upvar `.arg`: 8192 bytes
print-type-size variant `Suspend0`: 16385 bytes
print-type-size upvar `.arg`: 8192 bytes
print-type-size local `.arg`: 8192 bytes
print-type-size local `.__awaitee`: 1 bytes
print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async.rs:8:17: 8:19}
print-type-size variant `Returned`: 8192 bytes
print-type-size upvar `.arg`: 8192 bytes
print-type-size variant `Panicked`: 8192 bytes
Expand Down

0 comments on commit 6f506a6

Please sign in to comment.