Skip to content

Commit

Permalink
Rollup merge of #71942 - nnethercote:shrink-LocalDecl, r=matthewjasper
Browse files Browse the repository at this point in the history
Shrink `LocalDecl`

`LocalDecl` contributes 4-8% of peak heap memory usage on a range of benchmarks. This PR reduces its size from 128 bytes to 56 bytes on 64-bit, and does some clean-ups as well.

r? @matthewjasper
  • Loading branch information
Dylan-DPC authored May 9, 2020
2 parents d16d02b + 001496c commit 2b3a114
Show file tree
Hide file tree
Showing 25 changed files with 206 additions and 267 deletions.
116 changes: 57 additions & 59 deletions src/librustc_middle/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,13 @@ pub struct SourceInfo {
pub scope: SourceScope,
}

impl SourceInfo {
#[inline]
pub fn outermost(span: Span) -> Self {
SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }
}
}

///////////////////////////////////////////////////////////////////////////
// Borrow kinds

Expand Down Expand Up @@ -689,7 +696,7 @@ pub struct LocalDecl<'tcx> {
pub mutability: Mutability,

// FIXME(matthewjasper) Don't store in this in `Body`
pub local_info: LocalInfo<'tcx>,
pub local_info: Option<Box<LocalInfo<'tcx>>>,

/// `true` if this is an internal local.
///
Expand Down Expand Up @@ -725,7 +732,7 @@ pub struct LocalDecl<'tcx> {
/// borrow checker needs this information since it can affect
/// region inference.
// FIXME(matthewjasper) Don't store in this in `Body`
pub user_ty: UserTypeProjections,
pub user_ty: Option<Box<UserTypeProjections>>,

/// The *syntactic* (i.e., not visibility) source scope the local is defined
/// in. If the local was defined in a let-statement, this
Expand Down Expand Up @@ -809,7 +816,13 @@ pub struct LocalDecl<'tcx> {
pub source_info: SourceInfo,
}

/// Extra information about a local that's used for diagnostics.
// `LocalDecl` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
static_assert_size!(LocalDecl<'_>, 56);

/// Extra information about a some locals that's used for diagnostics. (Not
/// used for non-StaticRef temporaries, the return place, or anonymous function
/// parameters.)
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub enum LocalInfo<'tcx> {
/// A user-defined local variable or function parameter
Expand All @@ -820,8 +833,6 @@ pub enum LocalInfo<'tcx> {
User(ClearCrossCrate<BindingForm<'tcx>>),
/// A temporary created that references the static with the given `DefId`.
StaticRef { def_id: DefId, is_thread_local: bool },
/// Any other temporary, the return place, or an anonymous function parameter.
Other,
}

impl<'tcx> LocalDecl<'tcx> {
Expand All @@ -833,16 +844,16 @@ impl<'tcx> LocalDecl<'tcx> {
/// - or `match ... { C(x) => ... }`
pub fn can_be_made_mutable(&self) -> bool {
match self.local_info {
LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
}))) => true,
})))) => true,

LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
ImplicitSelfKind::Imm,
))) => true,
)))) => true,

_ => false,
}
Expand All @@ -853,14 +864,14 @@ impl<'tcx> LocalDecl<'tcx> {
/// mutable bindings, but the inverse does not necessarily hold).
pub fn is_nonref_binding(&self) -> bool {
match self.local_info {
LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
}))) => true,
})))) => true,

LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_)))) => true,

_ => false,
}
Expand All @@ -871,7 +882,7 @@ impl<'tcx> LocalDecl<'tcx> {
#[inline]
pub fn is_user_variable(&self) -> bool {
match self.local_info {
LocalInfo::User(_) => true,
Some(box LocalInfo::User(_)) => true,
_ => false,
}
}
Expand All @@ -881,7 +892,7 @@ impl<'tcx> LocalDecl<'tcx> {
/// match arm.
pub fn is_ref_for_guard(&self) -> bool {
match self.local_info {
LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))) => true,
_ => false,
}
}
Expand All @@ -890,7 +901,7 @@ impl<'tcx> LocalDecl<'tcx> {
/// access that static
pub fn is_ref_to_static(&self) -> bool {
match self.local_info {
LocalInfo::StaticRef { .. } => true,
Some(box LocalInfo::StaticRef { .. }) => true,
_ => false,
}
}
Expand All @@ -899,7 +910,7 @@ impl<'tcx> LocalDecl<'tcx> {
/// access that static
pub fn is_ref_to_thread_local(&self) -> bool {
match self.local_info {
LocalInfo::StaticRef { is_thread_local, .. } => is_thread_local,
Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local,
_ => false,
}
}
Expand All @@ -911,10 +922,31 @@ impl<'tcx> LocalDecl<'tcx> {
self.source_info.span.desugaring_kind().is_some()
}

/// Creates a new `LocalDecl` for a temporary.
/// Creates a new `LocalDecl` for a temporary: mutable, non-internal.
#[inline]
pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self {
Self::new_local(ty, Mutability::Mut, false, span)
pub fn new(ty: Ty<'tcx>, span: Span) -> Self {
Self::with_source_info(ty, SourceInfo::outermost(span))
}

/// Like `LocalDecl::new`, but takes a `SourceInfo` instead of a `Span`.
#[inline]
pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self {
LocalDecl {
mutability: Mutability::Mut,
local_info: None,
internal: false,
is_block_tail: None,
ty,
user_ty: None,
source_info,
}
}

/// Converts `self` into same `LocalDecl` except tagged as internal.
#[inline]
pub fn internal(mut self) -> Self {
self.internal = true;
self
}

/// Converts `self` into same `LocalDecl` except tagged as immutable.
Expand All @@ -931,41 +963,6 @@ impl<'tcx> LocalDecl<'tcx> {
self.is_block_tail = Some(info);
self
}

/// Creates a new `LocalDecl` for a internal temporary.
#[inline]
pub fn new_internal(ty: Ty<'tcx>, span: Span) -> Self {
Self::new_local(ty, Mutability::Mut, true, span)
}

#[inline]
fn new_local(ty: Ty<'tcx>, mutability: Mutability, internal: bool, span: Span) -> Self {
LocalDecl {
mutability,
ty,
user_ty: UserTypeProjections::none(),
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
internal,
local_info: LocalInfo::Other,
is_block_tail: None,
}
}

/// Builds a `LocalDecl` for the return place.
///
/// This must be inserted into the `local_decls` list as the first local.
#[inline]
pub fn new_return_place(return_ty: Ty<'_>, span: Span) -> LocalDecl<'_> {
LocalDecl {
mutability: Mutability::Mut,
ty: return_ty,
user_ty: UserTypeProjections::none(),
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
internal: false,
is_block_tail: None,
local_info: LocalInfo::Other,
}
}
}

/// Debug information pertaining to a user variable.
Expand Down Expand Up @@ -1406,10 +1403,7 @@ impl<'tcx> BasicBlockData<'tcx> {
let mut gap = self.statements.len()..self.statements.len() + extra_stmts;
self.statements.resize(
gap.end,
Statement {
source_info: SourceInfo { span: DUMMY_SP, scope: OUTERMOST_SOURCE_SCOPE },
kind: StatementKind::Nop,
},
Statement { source_info: SourceInfo::outermost(DUMMY_SP), kind: StatementKind::Nop },
);
for (splice_start, new_stmts) in splices.into_iter().rev() {
let splice_end = splice_start + new_stmts.size_hint().0;
Expand Down Expand Up @@ -2457,14 +2451,18 @@ impl Constant<'tcx> {
/// &'static str`.
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct UserTypeProjections {
pub(crate) contents: Vec<(UserTypeProjection, Span)>,
pub contents: Vec<(UserTypeProjection, Span)>,
}

impl<'tcx> UserTypeProjections {
pub fn none() -> Self {
UserTypeProjections { contents: vec![] }
}

pub fn is_empty(&self) -> bool {
self.contents.is_empty()
}

pub fn from_projections(projs: impl Iterator<Item = (UserTypeProjection, Span)>) -> Self {
UserTypeProjections { contents: projs.collect() }
}
Expand Down
22 changes: 12 additions & 10 deletions src/librustc_middle/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,10 @@ macro_rules! make_mir_visitor {
) {
let span = body.span;
if let Some(yield_ty) = &$($mutability)? body.yield_ty {
self.visit_ty(yield_ty, TyContext::YieldTy(SourceInfo {
span,
scope: OUTERMOST_SOURCE_SCOPE,
}));
self.visit_ty(
yield_ty,
TyContext::YieldTy(SourceInfo::outermost(span))
);
}

// for best performance, we want to use an iterator rather
Expand All @@ -263,10 +263,10 @@ macro_rules! make_mir_visitor {
self.visit_source_scope_data(scope);
}

self.visit_ty(&$($mutability)? body.return_ty(), TyContext::ReturnTy(SourceInfo {
span: body.span,
scope: OUTERMOST_SOURCE_SCOPE,
}));
self.visit_ty(
&$($mutability)? body.return_ty(),
TyContext::ReturnTy(SourceInfo::outermost(body.span))
);

for local in body.local_decls.indices() {
self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
Expand Down Expand Up @@ -715,8 +715,10 @@ macro_rules! make_mir_visitor {
local,
source_info: *source_info,
});
for (user_ty, _) in & $($mutability)? user_ty.contents {
self.visit_user_type_projection(user_ty);
if let Some(user_ty) = user_ty {
for (user_ty, _) in & $($mutability)? user_ty.contents {
self.visit_user_type_projection(user_ty);
}
}
self.visit_source_info(source_info);
}
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1447,15 +1447,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let (place_description, assigned_span) = match local_decl {
Some(LocalDecl {
local_info:
LocalInfo::User(
Some(box LocalInfo::User(
ClearCrossCrate::Clear
| ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
opt_match_place: None,
..
})),
)
| LocalInfo::StaticRef { .. }
| LocalInfo::Other,
))
| Some(box LocalInfo::StaticRef { .. })
| None,
..
})
| None => (self.describe_any_place(place.as_ref()), assigned_span),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/borrow_check/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if self.body.local_decls[local].is_ref_to_static() =>
{
let local_info = &self.body.local_decls[local].local_info;
if let LocalInfo::StaticRef { def_id, .. } = *local_info {
if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
} else {
unreachable!();
Expand Down
11 changes: 5 additions & 6 deletions src/librustc_mir/borrow_check/diagnostics/move_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
//
// opt_match_place is None for let [mut] x = ... statements,
// whether or not the right-hand side is a place expression
if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm {
opt_match_place: Some((opt_match_place, match_span)),
binding_mode: _,
opt_ty_info: _,
pat_span: _,
},
))) = local_decl.local_info
)))) = local_decl.local_info
{
let stmt_source_info = self.body.source_info(location);
self.append_binding_error(
Expand Down Expand Up @@ -482,10 +482,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
for local in binds_to {
let bind_to = &self.body.local_decls[*local];
if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
pat_span,
..
}))) = bind_to.local_info
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm { pat_span, .. },
)))) = bind_to.local_info
{
if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
{
Expand Down
Loading

0 comments on commit 2b3a114

Please sign in to comment.