Skip to content

Commit

Permalink
remove layout_cache and fix -Z print-type-sizes
Browse files Browse the repository at this point in the history
now we grow the type-sizes info during execution, rather than walking
the cache after the fact
  • Loading branch information
nikomatsakis committed Jun 1, 2017
1 parent 5fb0f0d commit c1e895d
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 200 deletions.
4 changes: 0 additions & 4 deletions src/librustc/ty/context.rs
Expand Up @@ -519,9 +519,6 @@ pub struct GlobalCtxt<'tcx> {
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,

/// Cache for layouts computed from types.
pub layout_cache: RefCell<FxHashMap<Ty<'tcx>, &'tcx Layout>>,

/// Used to prevent layout from recursing too deeply.
pub layout_depth: Cell<usize>,

Expand Down Expand Up @@ -718,7 +715,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
rvalue_promotable_to_static: RefCell::new(NodeMap()),
crate_name: Symbol::intern(crate_name),
data_layout: data_layout,
layout_cache: RefCell::new(FxHashMap()),
layout_interner: RefCell::new(FxHashSet()),
layout_depth: Cell::new(0),
derive_macros: RefCell::new(NodeMap()),
Expand Down
217 changes: 215 additions & 2 deletions src/librustc/ty/layout.rs
Expand Up @@ -12,10 +12,10 @@ pub use self::Integer::*;
pub use self::Layout::*;
pub use self::Primitive::*;

use session::Session;
use session::{self, DataTypeKind, Session};
use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags};

use syntax::ast::{FloatTy, IntTy, UintTy};
use syntax::ast::{self, FloatTy, IntTy, UintTy};
use syntax::attr;
use syntax_pos::DUMMY_SP;

Expand Down Expand Up @@ -1690,6 +1690,219 @@ impl<'a, 'tcx> Layout {
}
}
}

/// This is invoked by the `layout_raw` query to record the final
/// layout of each type.
#[inline]
pub fn record_layout_for_printing(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
layout: &Layout) {
// If we are running with `-Zprint-type-sizes`, record layouts for
// dumping later. Ignore layouts that are done with non-empty
// environments or non-monomorphic layouts, as the user only wants
// to see the stuff resulting from the final trans session.
if
!tcx.sess.opts.debugging_opts.print_type_sizes ||
ty.has_param_types() ||
ty.has_self_ty() ||
!param_env.caller_bounds.is_empty()
{
return;
}

Self::record_layout_for_printing_outlined(tcx, ty, param_env, layout)
}

fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
layout: &Layout) {
// (delay format until we actually need it)
let record = |kind, opt_discr_size, variants| {
let type_desc = format!("{:?}", ty);
let overall_size = layout.size(tcx);
let align = layout.align(tcx);
tcx.sess.code_stats.borrow_mut().record_type_size(kind,
type_desc,
align,
overall_size,
opt_discr_size,
variants);
};

let (adt_def, substs) = match ty.sty {
ty::TyAdt(ref adt_def, substs) => {
debug!("print-type-size t: `{:?}` process adt", ty);
(adt_def, substs)
}

ty::TyClosure(..) => {
debug!("print-type-size t: `{:?}` record closure", ty);
record(DataTypeKind::Closure, None, vec![]);
return;
}

_ => {
debug!("print-type-size t: `{:?}` skip non-nominal", ty);
return;
}
};

let adt_kind = adt_def.adt_kind();

let build_field_info = |(field_name, field_ty): (ast::Name, Ty<'tcx>), offset: &Size| {
let layout = field_ty.layout(tcx, param_env);
match layout {
Err(_) => bug!("no layout found for field {} type: `{:?}`", field_name, field_ty),
Ok(field_layout) => {
session::FieldInfo {
name: field_name.to_string(),
offset: offset.bytes(),
size: field_layout.size(tcx).bytes(),
align: field_layout.align(tcx).abi(),
}
}
}
};

let build_primitive_info = |name: ast::Name, value: &Primitive| {
session::VariantInfo {
name: Some(name.to_string()),
kind: session::SizeKind::Exact,
align: value.align(tcx).abi(),
size: value.size(tcx).bytes(),
fields: vec![],
}
};

enum Fields<'a> {
WithDiscrim(&'a Struct),
NoDiscrim(&'a Struct),
}

let build_variant_info = |n: Option<ast::Name>,
flds: &[(ast::Name, Ty<'tcx>)],
layout: Fields| {
let (s, field_offsets) = match layout {
Fields::WithDiscrim(s) => (s, &s.offsets[1..]),
Fields::NoDiscrim(s) => (s, &s.offsets[0..]),
};
let field_info: Vec<_> = flds.iter()
.zip(field_offsets.iter())
.map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset))
.collect();

session::VariantInfo {
name: n.map(|n|n.to_string()),
kind: if s.sized {
session::SizeKind::Exact
} else {
session::SizeKind::Min
},
align: s.align.abi(),
size: s.min_size.bytes(),
fields: field_info,
}
};

match *layout {
Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
nndiscr,
discrfield: _,
discrfield_source: _ } => {
debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
ty, nndiscr, variant_layout);
let variant_def = &adt_def.variants[nndiscr as usize];
let fields: Vec<_> = variant_def.fields.iter()
.map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
.collect();
record(adt_kind.into(),
None,
vec![build_variant_info(Some(variant_def.name),
&fields,
Fields::NoDiscrim(variant_layout))]);
}
Layout::RawNullablePointer { nndiscr, value } => {
debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}",
ty, nndiscr, value);
let variant_def = &adt_def.variants[nndiscr as usize];
record(adt_kind.into(), None,
vec![build_primitive_info(variant_def.name, &value)]);
}
Layout::Univariant { variant: ref variant_layout, non_zero: _ } => {
let variant_names = || {
adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
};
debug!("print-type-size t: `{:?}` adt univariant {:?} variants: {:?}",
ty, variant_layout, variant_names());
assert!(adt_def.variants.len() <= 1,
"univariant with variants {:?}", variant_names());
if adt_def.variants.len() == 1 {
let variant_def = &adt_def.variants[0];
let fields: Vec<_> = variant_def.fields.iter()
.map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
.collect();
record(adt_kind.into(),
None,
vec![build_variant_info(Some(variant_def.name),
&fields,
Fields::NoDiscrim(variant_layout))]);
} else {
// (This case arises for *empty* enums; so give it
// zero variants.)
record(adt_kind.into(), None, vec![]);
}
}

Layout::General { ref variants, discr, .. } => {
debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}",
ty, adt_def.variants.len(), variants.len(), variants);
let variant_infos: Vec<_> = adt_def.variants.iter()
.zip(variants.iter())
.map(|(variant_def, variant_layout)| {
let fields: Vec<_> = variant_def.fields.iter()
.map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
.collect();
build_variant_info(Some(variant_def.name),
&fields,
Fields::WithDiscrim(variant_layout))
})
.collect();
record(adt_kind.into(), Some(discr.size()), variant_infos);
}

Layout::UntaggedUnion { ref variants } => {
debug!("print-type-size t: `{:?}` adt union variants {:?}",
ty, variants);
// layout does not currently store info about each
// variant...
record(adt_kind.into(), None, Vec::new());
}

Layout::CEnum { discr, .. } => {
debug!("print-type-size t: `{:?}` adt c-like enum", ty);
let variant_infos: Vec<_> =
adt_def.variants.iter()
.map(|variant_def| {
build_primitive_info(variant_def.name,
&Primitive::Int(discr))
})
.collect();
record(adt_kind.into(), Some(discr.size()), variant_infos);
}

// other cases provide little interesting (i.e. adjustable
// via representation tweaks) size info beyond total size.
Layout::Scalar { .. } |
Layout::Vector { .. } |
Layout::Array { .. } |
Layout::FatPointer { .. } => {
debug!("print-type-size t: `{:?}` adt other", ty);
record(adt_kind.into(), None, Vec::new())
}
}
}
}

/// Type size "skeleton", i.e. the only information determining a type's size.
Expand Down
16 changes: 15 additions & 1 deletion src/librustc/ty/util.rs
Expand Up @@ -799,9 +799,22 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
param_env: ty::ParamEnv<'tcx>)
-> Result<&'tcx Layout, LayoutError<'tcx>> {
let ty = tcx.erase_regions(&self);
tcx.layout_raw(param_env.reveal_all().and(ty))
let layout = tcx.layout_raw(param_env.reveal_all().and(ty));

// NB: This recording is normally disabled; when enabled, it
// can however trigger recursive invocations of `layout()`.
// Therefore, we execute it *after* the main query has
// completed, to avoid problems around recursive structures
// and the like. (Admitedly, I wasn't able to reproduce a problem
// here, but it seems like the right thing to do. -nmatsakis)
if let Ok(l) = layout {
Layout::record_layout_for_printing(tcx, ty, param_env, l);
}

layout
}


/// Check whether a type is representable. This means it cannot contain unboxed
/// structural recursion. This check is needed for structs and enums.
pub fn is_representable(&'tcx self,
Expand Down Expand Up @@ -1084,6 +1097,7 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx.layout_depth.set(depth+1);
let layout = Layout::compute_uncached(tcx, param_env, ty);
tcx.layout_depth.set(depth);

layout
}

Expand Down

0 comments on commit c1e895d

Please sign in to comment.