Slightly reduce ItemTree memory footprint

This commit is contained in:
Jonas Schievink 2020-06-23 19:42:19 +02:00
parent f9a1a9cd3c
commit c019002d17
3 changed files with 68 additions and 53 deletions

View file

@ -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) => {

View file

@ -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<ModItem>,
top_attrs: Attrs,
attrs: FxHashMap<ModItem, Attrs>,
empty_attrs: Attrs,
inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>,
#[derive(Default, Debug, Eq, PartialEq)]
struct ItemTreeData {
imports: Arena<Import>,
extern_crates: Arena<ExternCrate>,
functions: Arena<Function>,
@ -63,6 +55,26 @@ pub struct ItemTree {
exprs: Arena<Expr>,
}
#[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<AttrOwner, Attrs>,
inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>,
data: Option<Box<ItemTreeData>>,
}
impl ItemTree {
pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
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>) -> &Self {
&tree.$fld[index]
&tree.data().$fld[index]
}
fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
@ -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]
}
}
)+

View file

@ -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<ModItems> {
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<FileItemTreeId<Enum>> {
@ -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<Idx<Variant>> {
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<FileItemTreeId<Static>> {
@ -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<Const> {
@ -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<FileItemTreeId<Mod>> {
@ -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<FileItemTreeId<Trait>> {
@ -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<FileItemTreeId<Impl>> {
@ -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<FileItemTreeId<Import>> {
@ -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<FileItemTreeId<MacroCall>> {
@ -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<ModItem> {
@ -619,10 +623,14 @@ impl Ctx {
}
fn next_field_idx(&self) -> Idx<Field> {
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<Variant> {
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),
))
}
}