From fb1f544e2479addd5957688e297ea04ddf0cf249 Mon Sep 17 00:00:00 2001 From: Alexandru Macovei Date: Tue, 30 Mar 2021 23:06:57 +0300 Subject: Use Box'es to reduce size of hir_def::expr::Expr from 128 to 72 bytes (on 64bit systems) Rationale: only a minority of variants used almost half the size. By keeping large members (especially in Option) behind a box the memory cost is only payed when the large variants are needed. This reduces the size Vec needs to allocate. --- crates/hir_def/src/body/lower.rs | 16 ++++++++++------ crates/hir_def/src/expr.rs | 8 ++++---- crates/hir_ty/src/infer/expr.rs | 10 ++++++++-- 3 files changed, 22 insertions(+), 12 deletions(-) (limited to 'crates') diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 63e89a1f4..73e7aee33 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -322,8 +322,10 @@ impl ExprCollector<'_> { Vec::new() }; let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); - let generic_args = - e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); + let generic_args = e + .generic_arg_list() + .and_then(|it| GenericArgs::from_ast(&self.ctx(), it)) + .map(Box::new); self.alloc_expr( Expr::MethodCall { receiver, method_name, args, generic_args }, syntax_ptr, @@ -385,7 +387,7 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::Yield { expr }, syntax_ptr) } ast::Expr::RecordExpr(e) => { - let path = e.path().and_then(|path| self.expander.parse_path(path)); + let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); let record_lit = if let Some(nfl) = e.record_expr_field_list() { let fields = nfl .fields() @@ -430,7 +432,7 @@ impl ExprCollector<'_> { } ast::Expr::CastExpr(e) => { let expr = self.collect_expr_opt(e.expr()); - let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); + let type_ref = Box::new(TypeRef::from_ast_opt(&self.ctx(), e.ty())); self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) } ast::Expr::RefExpr(e) => { @@ -469,8 +471,10 @@ impl ExprCollector<'_> { arg_types.push(type_ref); } } - let ret_type = - e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); + let ret_type = e + .ret_type() + .and_then(|r| r.ty()) + .map(|it| Box::new(TypeRef::from_ast(&self.ctx(), it))); let body = self.collect_expr_opt(e.body()); self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) } diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index 6c7376fad..ba00b9609 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs @@ -86,7 +86,7 @@ pub enum Expr { receiver: ExprId, method_name: Name, args: Vec, - generic_args: Option, + generic_args: Option>, }, Match { expr: ExprId, @@ -106,7 +106,7 @@ pub enum Expr { expr: Option, }, RecordLit { - path: Option, + path: Option>, fields: Vec, spread: Option, }, @@ -131,7 +131,7 @@ pub enum Expr { }, Cast { expr: ExprId, - type_ref: TypeRef, + type_ref: Box, }, Ref { expr: ExprId, @@ -162,7 +162,7 @@ pub enum Expr { Lambda { args: Vec, arg_types: Vec>, - ret_type: Option, + ret_type: Option>, body: ExprId, }, Tuple { diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index ff564106b..2fcc7c549 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs @@ -317,7 +317,13 @@ impl<'a> InferenceContext<'a> { self.normalize_associated_types_in(ret_ty) } Expr::MethodCall { receiver, args, method_name, generic_args } => self - .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), + .infer_method_call( + tgt_expr, + *receiver, + &args, + &method_name, + generic_args.as_deref(), + ), Expr::Match { expr, arms } => { let input_ty = self.infer_expr(*expr, &Expectation::none()); @@ -398,7 +404,7 @@ impl<'a> InferenceContext<'a> { TyKind::Never.intern(&Interner) } Expr::RecordLit { path, fields, spread } => { - let (ty, def_id) = self.resolve_variant(path.as_ref()); + let (ty, def_id) = self.resolve_variant(path.as_deref()); if let Some(variant) = def_id { self.write_variant_resolution(tgt_expr.into(), variant); } -- cgit v1.2.3 From 32304d14a1a5e316615028ffd7bcfcff682fbe56 Mon Sep 17 00:00:00 2001 From: Alexandru Macovei Date: Wed, 31 Mar 2021 00:55:18 +0300 Subject: Use Box'es to reduce the size of hir_def::expr::Pat from 112 to 64 bytes on 64bit --- crates/hir_def/src/body/lower.rs | 6 +++--- crates/hir_def/src/expr.rs | 6 +++--- crates/hir_def/src/path.rs | 6 ++++++ crates/hir_ty/src/infer/pat.rs | 4 ++-- 4 files changed, 14 insertions(+), 8 deletions(-) (limited to 'crates') diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 73e7aee33..1e743e5d5 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -759,7 +759,7 @@ impl ExprCollector<'_> { } } ast::Pat::TupleStructPat(p) => { - let path = p.path().and_then(|path| self.expander.parse_path(path)); + let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); let (args, ellipsis) = self.collect_tuple_pat(p.fields()); Pat::TupleStruct { path, args, ellipsis } } @@ -769,7 +769,7 @@ impl ExprCollector<'_> { Pat::Ref { pat, mutability } } ast::Pat::PathPat(p) => { - let path = p.path().and_then(|path| self.expander.parse_path(path)); + let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); path.map(Pat::Path).unwrap_or(Pat::Missing) } ast::Pat::OrPat(p) => { @@ -783,7 +783,7 @@ impl ExprCollector<'_> { } ast::Pat::WildcardPat(_) => Pat::Wild, ast::Pat::RecordPat(p) => { - let path = p.path().and_then(|path| self.expander.parse_path(path)); + let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); let args: Vec<_> = p .record_pat_field_list() .expect("every struct should have a field list") diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index ba00b9609..62a28bdba 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs @@ -412,13 +412,13 @@ pub enum Pat { Wild, Tuple { args: Vec, ellipsis: Option }, Or(Vec), - Record { path: Option, args: Vec, ellipsis: bool }, + Record { path: Option>, args: Vec, ellipsis: bool }, Range { start: ExprId, end: ExprId }, Slice { prefix: Vec, slice: Option, suffix: Vec }, - Path(Path), + Path(Box), Lit(ExprId), Bind { mode: BindingAnnotation, name: Name, subpat: Option }, - TupleStruct { path: Option, args: Vec, ellipsis: Option }, + TupleStruct { path: Option>, args: Vec, ellipsis: Option }, Ref { pat: PatId, mutability: Mutability }, Box { inner: PatId }, ConstBlock(ExprId), diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index f9c8328f0..b528ff8ba 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs @@ -289,6 +289,12 @@ impl From for Path { } } +impl From for Box { + fn from(name: Name) -> Box { + Box::new(Path::from(name)) + } +} + impl From for ModPath { fn from(name: Name) -> ModPath { ModPath::from_segments(PathKind::Plain, iter::once(name)) diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 252ae914a..afaf6b28b 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs @@ -174,7 +174,7 @@ impl<'a> InferenceContext<'a> { TyKind::Ref(mutability, subty).intern(&Interner) } Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat( - p.as_ref(), + p.as_deref(), subpats, expected, default_bm, @@ -182,7 +182,7 @@ impl<'a> InferenceContext<'a> { *ellipsis, ), Pat::Record { path: p, args: fields, ellipsis: _ } => { - self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) + self.infer_record_pat(p.as_deref(), fields, expected, default_bm, pat) } Pat::Path(path) => { // FIXME use correct resolver for the surrounding expression -- cgit v1.2.3 From 4e2a6ac7eae3ff193962421cc3c86e5d8f9a7e31 Mon Sep 17 00:00:00 2001 From: Alexandru Macovei Date: Thu, 1 Apr 2021 14:01:59 +0300 Subject: Avoid duplicating VfsPath in vfs::path_interner::PathInterner by using an IndexSet --- crates/vfs/Cargo.toml | 1 + crates/vfs/src/path_interner.rs | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'crates') diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index c318a68f7..894944b18 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -14,3 +14,4 @@ rustc-hash = "1.0" fst = "0.4" paths = { path = "../paths", version = "0.0.0" } +indexmap = "1.6.2" diff --git a/crates/vfs/src/path_interner.rs b/crates/vfs/src/path_interner.rs index 2189e5e25..6e049f0d4 100644 --- a/crates/vfs/src/path_interner.rs +++ b/crates/vfs/src/path_interner.rs @@ -1,15 +1,22 @@ //! Maps paths to compact integer ids. We don't care about clearings paths which //! no longer exist -- the assumption is total size of paths we ever look at is //! not too big. -use rustc_hash::FxHashMap; +use std::hash::BuildHasherDefault; + +use indexmap::IndexSet; +use rustc_hash::FxHasher; use crate::{FileId, VfsPath}; /// Structure to map between [`VfsPath`] and [`FileId`]. -#[derive(Default)] pub(crate) struct PathInterner { - map: FxHashMap, - vec: Vec, + map: IndexSet>, +} + +impl Default for PathInterner { + fn default() -> Self { + Self { map: IndexSet::default() } + } } impl PathInterner { @@ -17,7 +24,7 @@ impl PathInterner { /// /// If `path` does not exists in `self`, returns [`None`]. pub(crate) fn get(&self, path: &VfsPath) -> Option { - self.map.get(path).copied() + self.map.get_index_of(path).map(|i| FileId(i as u32)) } /// Insert `path` in `self`. @@ -25,13 +32,9 @@ impl PathInterner { /// - If `path` already exists in `self`, returns its associated id; /// - Else, returns a newly allocated id. pub(crate) fn intern(&mut self, path: VfsPath) -> FileId { - if let Some(id) = self.get(&path) { - return id; - } - let id = FileId(self.vec.len() as u32); - self.map.insert(path.clone(), id); - self.vec.push(path); - id + let (id, _added) = self.map.insert_full(path); + assert!(id < u32::MAX as usize); + FileId(id as u32) } /// Returns the path corresponding to `id`. @@ -40,6 +43,6 @@ impl PathInterner { /// /// Panics if `id` does not exists in `self`. pub(crate) fn lookup(&self, id: FileId) -> &VfsPath { - &self.vec[id.0 as usize] + self.map.get_index(id.0 as usize).unwrap() } } -- cgit v1.2.3