From c019002d17185f4e8be54a978ab5d67bc632f518 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 19:42:19 +0200 Subject: Slightly reduce ItemTree memory footprint --- crates/ra_hir_def/src/attr.rs | 2 + crates/ra_hir_def/src/item_tree.rs | 73 +++++++++++++++++--------------- crates/ra_hir_def/src/item_tree/lower.rs | 46 +++++++++++--------- 3 files changed, 68 insertions(+), 53 deletions(-) diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index e0f468bf3..197737ffc 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -38,6 +38,8 @@ impl ops::Deref for Attrs { } impl Attrs { + pub const EMPTY: Attrs = Attrs { entries: None }; + pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { match def { AttrDefId::ModuleId(module) => { diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs index a75271703..d55b3f777 100644 --- a/crates/ra_hir_def/src/item_tree.rs +++ b/crates/ra_hir_def/src/item_tree.rs @@ -35,16 +35,8 @@ use crate::{ }; use smallvec::SmallVec; -/// The item tree of a source file. -#[derive(Debug, Eq, PartialEq)] -pub struct ItemTree { - file_id: HirFileId, - top_level: Vec, - top_attrs: Attrs, - attrs: FxHashMap, - empty_attrs: Attrs, - inner_items: FxHashMap, SmallVec<[ModItem; 1]>>, - +#[derive(Default, Debug, Eq, PartialEq)] +struct ItemTreeData { imports: Arena, extern_crates: Arena, functions: Arena, @@ -63,6 +55,26 @@ pub struct ItemTree { exprs: Arena, } +#[derive(Debug, Eq, PartialEq, Hash)] +enum AttrOwner { + /// Attributes on an item. + ModItem(ModItem), + /// Inner attributes of the source file. + TopLevel, + // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`. +} + +/// The item tree of a source file. +#[derive(Debug, Eq, PartialEq)] +pub struct ItemTree { + file_id: HirFileId, + top_level: SmallVec<[ModItem; 1]>, + attrs: FxHashMap, + inner_items: FxHashMap, SmallVec<[ModItem; 1]>>, + + data: Option>, +} + impl ItemTree { pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id)); @@ -95,7 +107,9 @@ impl ItemTree { } }; - item_tree.top_attrs = top_attrs.unwrap_or_default(); + if let Some(attrs) = top_attrs { + item_tree.attrs.insert(AttrOwner::TopLevel, attrs); + } Arc::new(item_tree) } @@ -103,26 +117,9 @@ impl ItemTree { Self { file_id, top_level: Default::default(), - top_attrs: Default::default(), attrs: Default::default(), - empty_attrs: Default::default(), inner_items: Default::default(), - imports: Default::default(), - extern_crates: Default::default(), - functions: Default::default(), - structs: Default::default(), - fields: Default::default(), - unions: Default::default(), - enums: Default::default(), - variants: Default::default(), - consts: Default::default(), - statics: Default::default(), - traits: Default::default(), - impls: Default::default(), - type_aliases: Default::default(), - mods: Default::default(), - macro_calls: Default::default(), - exprs: Default::default(), + data: Default::default(), } } @@ -134,11 +131,11 @@ impl ItemTree { /// Returns the inner attributes of the source file. pub fn top_level_attrs(&self) -> &Attrs { - &self.top_attrs + self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY) } pub fn attrs(&self, of: ModItem) -> &Attrs { - self.attrs.get(&of).unwrap_or(&self.empty_attrs) + self.attrs.get(&AttrOwner::ModItem(of)).unwrap_or(&Attrs::EMPTY) } /// Returns the lowered inner items that `ast` corresponds to. @@ -169,6 +166,14 @@ impl ItemTree { let ptr = map.get(id); ptr.to_node(&root) } + + fn data(&self) -> &ItemTreeData { + self.data.as_ref().expect("attempted to access data of empty ItemTree") + } + + fn data_mut(&mut self) -> &mut ItemTreeData { + self.data.get_or_insert_with(Box::default) + } } /// Trait implemented by all nodes in the item tree. @@ -246,7 +251,7 @@ macro_rules! mod_items { } fn lookup(tree: &ItemTree, index: Idx) -> &Self { - &tree.$fld[index] + &tree.data().$fld[index] } fn id_from_mod_item(mod_item: ModItem) -> Option> { @@ -266,7 +271,7 @@ macro_rules! mod_items { type Output = $typ; fn index(&self, index: Idx<$typ>) -> &Self::Output { - &self.$fld[index] + &self.data().$fld[index] } } )+ @@ -296,7 +301,7 @@ macro_rules! impl_index { type Output = $t; fn index(&self, index: Idx<$t>) -> &Self::Output { - &self.$fld[index] + &self.data().$fld[index] } } )+ diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 733fcac7a..7d28fe7c6 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -66,6 +66,10 @@ impl Ctx { self.tree } + fn data(&mut self) -> &mut ItemTreeData { + self.tree.data_mut() + } + fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option { assert!(inner || self.inner_items.is_empty()); @@ -124,7 +128,7 @@ impl Ctx { } fn add_attrs(&mut self, item: ModItem, attrs: Attrs) { - match self.tree.attrs.entry(item) { + match self.tree.attrs.entry(AttrOwner::ModItem(item)) { Entry::Occupied(mut entry) => { *entry.get_mut() = entry.get().merge(attrs); } @@ -169,7 +173,7 @@ impl Ctx { ast::StructKind::Unit => StructDefKind::Unit, }; let res = Struct { name, visibility, generic_params, fields, ast_id, kind }; - Some(id(self.tree.structs.alloc(res))) + Some(id(self.data().structs.alloc(res))) } fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { @@ -190,7 +194,7 @@ impl Ctx { let start = self.next_field_idx(); for field in fields.fields() { if let Some(data) = self.lower_record_field(&field) { - self.tree.fields.alloc(data); + self.data().fields.alloc(data); } } let end = self.next_field_idx(); @@ -209,7 +213,7 @@ impl Ctx { let start = self.next_field_idx(); for (i, field) in fields.fields().enumerate() { if let Some(data) = self.lower_tuple_field(i, &field) { - self.tree.fields.alloc(data); + self.data().fields.alloc(data); } } let end = self.next_field_idx(); @@ -236,7 +240,7 @@ impl Ctx { }; let ast_id = self.source_ast_id_map.ast_id(union); let res = Union { name, visibility, generic_params, fields, ast_id }; - Some(id(self.tree.unions.alloc(res))) + Some(id(self.data().unions.alloc(res))) } fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option> { @@ -249,14 +253,14 @@ impl Ctx { }; let ast_id = self.source_ast_id_map.ast_id(enum_); let res = Enum { name, visibility, generic_params, variants, ast_id }; - Some(id(self.tree.enums.alloc(res))) + Some(id(self.data().enums.alloc(res))) } fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range> { let start = self.next_variant_idx(); for variant in variants.variants() { if let Some(data) = self.lower_variant(&variant) { - self.tree.variants.alloc(data); + self.data().variants.alloc(data); } } let end = self.next_variant_idx(); @@ -327,7 +331,7 @@ impl Ctx { }; res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); - Some(id(self.tree.functions.alloc(res))) + Some(id(self.data().functions.alloc(res))) } fn lower_type_alias( @@ -341,7 +345,7 @@ impl Ctx { let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id }; - Some(id(self.tree.type_aliases.alloc(res))) + Some(id(self.data().type_aliases.alloc(res))) } fn lower_static(&mut self, static_: &ast::StaticDef) -> Option> { @@ -351,7 +355,7 @@ impl Ctx { let mutable = static_.mut_token().is_some(); let ast_id = self.source_ast_id_map.ast_id(static_); let res = Static { name, visibility, mutable, type_ref, ast_id }; - Some(id(self.tree.statics.alloc(res))) + Some(id(self.data().statics.alloc(res))) } fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId { @@ -360,7 +364,7 @@ impl Ctx { let visibility = self.lower_visibility(konst); let ast_id = self.source_ast_id_map.ast_id(konst); let res = Const { name, visibility, type_ref, ast_id }; - id(self.tree.consts.alloc(res)) + id(self.data().consts.alloc(res)) } fn lower_module(&mut self, module: &ast::Module) -> Option> { @@ -386,7 +390,7 @@ impl Ctx { }; let ast_id = self.source_ast_id_map.ast_id(module); let res = Mod { name, visibility, kind, ast_id }; - Some(id(self.tree.mods.alloc(res))) + Some(id(self.data().mods.alloc(res))) } fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option> { @@ -417,7 +421,7 @@ impl Ctx { items: items.unwrap_or_default(), ast_id, }; - Some(id(self.tree.traits.alloc(res))) + Some(id(self.data().traits.alloc(res))) } fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option> { @@ -440,7 +444,7 @@ impl Ctx { .collect(); let ast_id = self.source_ast_id_map.ast_id(impl_def); let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; - Some(id(self.tree.impls.alloc(res))) + Some(id(self.data().impls.alloc(res))) } fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec> { @@ -451,7 +455,7 @@ impl Ctx { // Every use item can expand to many `Import`s. let mut imports = Vec::new(); - let tree = &mut self.tree; + let tree = self.tree.data_mut(); ModPath::expand_use_item( InFile::new(self.file, use_item.clone()), &self.hygiene, @@ -484,7 +488,7 @@ impl Ctx { let is_macro_use = extern_crate.has_atom_attr("macro_use"); let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id }; - Some(id(self.tree.extern_crates.alloc(res))) + Some(id(self.data().extern_crates.alloc(res))) } fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option> { @@ -511,7 +515,7 @@ impl Ctx { let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }; - Some(id(self.tree.macro_calls.alloc(res))) + Some(id(self.data().macro_calls.alloc(res))) } fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec { @@ -619,10 +623,14 @@ impl Ctx { } fn next_field_idx(&self) -> Idx { - Idx::from_raw(RawId::from(self.tree.fields.len() as u32)) + Idx::from_raw(RawId::from( + self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32), + )) } fn next_variant_idx(&self) -> Idx { - Idx::from_raw(RawId::from(self.tree.variants.len() as u32)) + Idx::from_raw(RawId::from( + self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), + )) } } -- cgit v1.2.3