aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-02-04 18:33:57 +0000
committerGitHub <[email protected]>2021-02-04 18:33:57 +0000
commit36191543a679d4e01c206d2e98a2d7ae170a25e2 (patch)
tree91431506bde2965c819030eea14433926b82310f
parent663d404a4ee52cf96e0de793e45290be1a43dcb5 (diff)
parent003ee0086ae424ec43ad14cd90af9cd5809a93c8 (diff)
Merge #7557
7557: Intern `TypeRef`s in the containing `ItemTree` r=jonas-schievink a=jonas-schievink This reduces the memory used by `ItemTreeQuery` by ~20%. As it turns out, `TypeRef` is very heavy, and is used a lot in `ItemTree`: * Many types are frequently repeated throughout the same file. This is what this PR addresses by storing identical `TypeRef`s only once per `ItemTree`. * The vast majority of `TypeRef` consist of a plain path with only a single element. "Type anchors" like in `<Ty>::func` are used incredibly rarely, and even multi-segment paths are much rarer than single-segment paths. Co-authored-by: Jonas Schievink <[email protected]>
-rw-r--r--crates/hir_def/src/adt.rs2
-rw-r--r--crates/hir_def/src/data.rs14
-rw-r--r--crates/hir_def/src/item_tree.rs54
-rw-r--r--crates/hir_def/src/item_tree/lower.rs18
4 files changed, 67 insertions, 21 deletions
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs
index 06f0b9b18..ed36c3109 100644
--- a/crates/hir_def/src/adt.rs
+++ b/crates/hir_def/src/adt.rs
@@ -351,7 +351,7 @@ fn lower_field(
351) -> FieldData { 351) -> FieldData {
352 FieldData { 352 FieldData {
353 name: field.name.clone(), 353 name: field.name.clone(),
354 type_ref: field.type_ref.clone(), 354 type_ref: item_tree[field.type_ref].clone(),
355 visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), 355 visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
356 } 356 }
357} 357}
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index c2b0dc007..42fcca386 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -41,8 +41,8 @@ impl FunctionData {
41 41
42 Arc::new(FunctionData { 42 Arc::new(FunctionData {
43 name: func.name.clone(), 43 name: func.name.clone(),
44 params: func.params.to_vec(), 44 params: func.params.iter().map(|id| item_tree[*id].clone()).collect(),
45 ret_type: func.ret_type.clone(), 45 ret_type: item_tree[func.ret_type].clone(),
46 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()).clone(), 46 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()).clone(),
47 has_self_param: func.has_self_param, 47 has_self_param: func.has_self_param,
48 has_body: func.has_body, 48 has_body: func.has_body,
@@ -75,7 +75,7 @@ impl TypeAliasData {
75 75
76 Arc::new(TypeAliasData { 76 Arc::new(TypeAliasData {
77 name: typ.name.clone(), 77 name: typ.name.clone(),
78 type_ref: typ.type_ref.clone(), 78 type_ref: typ.type_ref.map(|id| item_tree[id].clone()),
79 visibility: item_tree[typ.visibility].clone(), 79 visibility: item_tree[typ.visibility].clone(),
80 is_extern: typ.is_extern, 80 is_extern: typ.is_extern,
81 bounds: typ.bounds.to_vec(), 81 bounds: typ.bounds.to_vec(),
@@ -144,8 +144,8 @@ impl ImplData {
144 144
145 let item_tree = db.item_tree(impl_loc.id.file_id); 145 let item_tree = db.item_tree(impl_loc.id.file_id);
146 let impl_def = &item_tree[impl_loc.id.value]; 146 let impl_def = &item_tree[impl_loc.id.value];
147 let target_trait = impl_def.target_trait.clone(); 147 let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone());
148 let target_type = impl_def.target_type.clone(); 148 let target_type = item_tree[impl_def.target_type].clone();
149 let is_negative = impl_def.is_negative; 149 let is_negative = impl_def.is_negative;
150 let module_id = impl_loc.container.module(db); 150 let module_id = impl_loc.container.module(db);
151 let container = AssocContainerId::ImplId(id); 151 let container = AssocContainerId::ImplId(id);
@@ -182,7 +182,7 @@ impl ConstData {
182 182
183 Arc::new(ConstData { 183 Arc::new(ConstData {
184 name: konst.name.clone(), 184 name: konst.name.clone(),
185 type_ref: konst.type_ref.clone(), 185 type_ref: item_tree[konst.type_ref].clone(),
186 visibility: item_tree[konst.visibility].clone(), 186 visibility: item_tree[konst.visibility].clone(),
187 }) 187 })
188 } 188 }
@@ -205,7 +205,7 @@ impl StaticData {
205 205
206 Arc::new(StaticData { 206 Arc::new(StaticData {
207 name: Some(statik.name.clone()), 207 name: Some(statik.name.clone()),
208 type_ref: statik.type_ref.clone(), 208 type_ref: item_tree[statik.type_ref].clone(),
209 visibility: item_tree[statik.visibility].clone(), 209 visibility: item_tree[statik.visibility].clone(),
210 mutable: statik.mutable, 210 mutable: statik.mutable,
211 is_extern: statik.is_extern, 211 is_extern: statik.is_extern,
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 4bde67649..401556931 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -146,6 +146,7 @@ impl ItemTree {
146 macro_defs, 146 macro_defs,
147 vis, 147 vis,
148 generics, 148 generics,
149 type_refs,
149 inner_items, 150 inner_items,
150 } = &mut **data; 151 } = &mut **data;
151 152
@@ -169,6 +170,8 @@ impl ItemTree {
169 170
170 vis.arena.shrink_to_fit(); 171 vis.arena.shrink_to_fit();
171 generics.arena.shrink_to_fit(); 172 generics.arena.shrink_to_fit();
173 type_refs.arena.shrink_to_fit();
174 type_refs.map.shrink_to_fit();
172 175
173 inner_items.shrink_to_fit(); 176 inner_items.shrink_to_fit();
174 } 177 }
@@ -279,6 +282,32 @@ static EMPTY_GENERICS: GenericParams = GenericParams {
279 where_predicates: Vec::new(), 282 where_predicates: Vec::new(),
280}; 283};
281 284
285/// `TypeRef` interner.
286#[derive(Default, Debug, Eq, PartialEq)]
287struct TypeRefStorage {
288 arena: Arena<Arc<TypeRef>>,
289 map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>,
290}
291
292impl TypeRefStorage {
293 // Note: We lie about the `Idx<TypeRef>` to hide the interner details.
294
295 fn intern(&mut self, ty: TypeRef) -> Idx<TypeRef> {
296 if let Some(id) = self.map.get(&ty) {
297 return Idx::from_raw(id.into_raw());
298 }
299
300 let ty = Arc::new(ty);
301 let idx = self.arena.alloc(ty.clone());
302 self.map.insert(ty, idx);
303 Idx::from_raw(idx.into_raw())
304 }
305
306 fn lookup(&self, id: Idx<TypeRef>) -> &TypeRef {
307 &self.arena[Idx::from_raw(id.into_raw())]
308 }
309}
310
282#[derive(Default, Debug, Eq, PartialEq)] 311#[derive(Default, Debug, Eq, PartialEq)]
283struct ItemTreeData { 312struct ItemTreeData {
284 imports: Arena<Import>, 313 imports: Arena<Import>,
@@ -301,6 +330,7 @@ struct ItemTreeData {
301 330
302 vis: ItemVisibilities, 331 vis: ItemVisibilities,
303 generics: GenericParamsStorage, 332 generics: GenericParamsStorage,
333 type_refs: TypeRefStorage,
304 334
305 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, 335 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
306} 336}
@@ -489,6 +519,14 @@ impl Index<GenericParamsId> for ItemTree {
489 } 519 }
490} 520}
491 521
522impl Index<Idx<TypeRef>> for ItemTree {
523 type Output = TypeRef;
524
525 fn index(&self, id: Idx<TypeRef>) -> &Self::Output {
526 self.data().type_refs.lookup(id)
527 }
528}
529
492impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { 530impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
493 type Output = N; 531 type Output = N;
494 fn index(&self, id: FileItemTreeId<N>) -> &N { 532 fn index(&self, id: FileItemTreeId<N>) -> &N {
@@ -532,9 +570,9 @@ pub struct Function {
532 /// Whether the function is located in an `extern` block (*not* whether it is an 570 /// Whether the function is located in an `extern` block (*not* whether it is an
533 /// `extern "abi" fn`). 571 /// `extern "abi" fn`).
534 pub is_extern: bool, 572 pub is_extern: bool,
535 pub params: Box<[TypeRef]>, 573 pub params: Box<[Idx<TypeRef>]>,
536 pub is_varargs: bool, 574 pub is_varargs: bool,
537 pub ret_type: TypeRef, 575 pub ret_type: Idx<TypeRef>,
538 pub ast_id: FileAstId<ast::Fn>, 576 pub ast_id: FileAstId<ast::Fn>,
539} 577}
540 578
@@ -581,7 +619,7 @@ pub struct Const {
581 /// const _: () = (); 619 /// const _: () = ();
582 pub name: Option<Name>, 620 pub name: Option<Name>,
583 pub visibility: RawVisibilityId, 621 pub visibility: RawVisibilityId,
584 pub type_ref: TypeRef, 622 pub type_ref: Idx<TypeRef>,
585 pub ast_id: FileAstId<ast::Const>, 623 pub ast_id: FileAstId<ast::Const>,
586} 624}
587 625
@@ -592,7 +630,7 @@ pub struct Static {
592 pub mutable: bool, 630 pub mutable: bool,
593 /// Whether the static is in an `extern` block. 631 /// Whether the static is in an `extern` block.
594 pub is_extern: bool, 632 pub is_extern: bool,
595 pub type_ref: TypeRef, 633 pub type_ref: Idx<TypeRef>,
596 pub ast_id: FileAstId<ast::Static>, 634 pub ast_id: FileAstId<ast::Static>,
597} 635}
598 636
@@ -609,8 +647,8 @@ pub struct Trait {
609#[derive(Debug, Clone, Eq, PartialEq)] 647#[derive(Debug, Clone, Eq, PartialEq)]
610pub struct Impl { 648pub struct Impl {
611 pub generic_params: GenericParamsId, 649 pub generic_params: GenericParamsId,
612 pub target_trait: Option<TypeRef>, 650 pub target_trait: Option<Idx<TypeRef>>,
613 pub target_type: TypeRef, 651 pub target_type: Idx<TypeRef>,
614 pub is_negative: bool, 652 pub is_negative: bool,
615 pub items: Box<[AssocItem]>, 653 pub items: Box<[AssocItem]>,
616 pub ast_id: FileAstId<ast::Impl>, 654 pub ast_id: FileAstId<ast::Impl>,
@@ -623,7 +661,7 @@ pub struct TypeAlias {
623 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. 661 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
624 pub bounds: Box<[TypeBound]>, 662 pub bounds: Box<[TypeBound]>,
625 pub generic_params: GenericParamsId, 663 pub generic_params: GenericParamsId,
626 pub type_ref: Option<TypeRef>, 664 pub type_ref: Option<Idx<TypeRef>>,
627 pub is_extern: bool, 665 pub is_extern: bool,
628 pub ast_id: FileAstId<ast::TypeAlias>, 666 pub ast_id: FileAstId<ast::TypeAlias>,
629} 667}
@@ -806,6 +844,6 @@ pub enum Fields {
806#[derive(Debug, Clone, PartialEq, Eq)] 844#[derive(Debug, Clone, PartialEq, Eq)]
807pub struct Field { 845pub struct Field {
808 pub name: Name, 846 pub name: Name,
809 pub type_ref: TypeRef, 847 pub type_ref: Idx<TypeRef>,
810 pub visibility: RawVisibilityId, 848 pub visibility: RawVisibilityId,
811} 849}
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index de2177933..93cdca55d 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -364,6 +364,7 @@ impl Ctx {
364 params.push(type_ref); 364 params.push(type_ref);
365 } 365 }
366 } 366 }
367 let params = params.into_iter().map(|param| self.data().type_refs.intern(param)).collect();
367 368
368 let mut is_varargs = false; 369 let mut is_varargs = false;
369 if let Some(params) = func.param_list() { 370 if let Some(params) = func.param_list() {
@@ -385,6 +386,8 @@ impl Ctx {
385 ret_type 386 ret_type
386 }; 387 };
387 388
389 let ret_type = self.data().type_refs.intern(ret_type);
390
388 let has_body = func.body().is_some(); 391 let has_body = func.body().is_some();
389 392
390 let ast_id = self.source_ast_id_map.ast_id(func); 393 let ast_id = self.source_ast_id_map.ast_id(func);
@@ -396,7 +399,7 @@ impl Ctx {
396 has_body, 399 has_body,
397 is_unsafe: func.unsafe_token().is_some(), 400 is_unsafe: func.unsafe_token().is_some(),
398 is_extern: false, 401 is_extern: false,
399 params: params.into_boxed_slice(), 402 params,
400 is_varargs, 403 is_varargs,
401 ret_type, 404 ret_type,
402 ast_id, 405 ast_id,
@@ -657,6 +660,7 @@ impl Ctx {
657 generics.fill(&self.body_ctx, sm, node); 660 generics.fill(&self.body_ctx, sm, node);
658 // lower `impl Trait` in arguments 661 // lower `impl Trait` in arguments
659 for param in &*func.params { 662 for param in &*func.params {
663 let param = self.data().type_refs.lookup(*param);
660 generics.fill_implicit_impl_trait_args(param); 664 generics.fill_implicit_impl_trait_args(param);
661 } 665 }
662 } 666 }
@@ -709,11 +713,15 @@ impl Ctx {
709 self.data().vis.alloc(vis) 713 self.data().vis.alloc(vis)
710 } 714 }
711 715
712 fn lower_type_ref(&self, type_ref: &ast::Type) -> TypeRef { 716 fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> {
713 TypeRef::from_ast(&self.body_ctx, type_ref.clone()) 717 let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
718 self.data().type_refs.intern(tyref)
714 } 719 }
715 fn lower_type_ref_opt(&self, type_ref: Option<ast::Type>) -> TypeRef { 720 fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> {
716 type_ref.map(|ty| self.lower_type_ref(&ty)).unwrap_or(TypeRef::Error) 721 match type_ref.map(|ty| self.lower_type_ref(&ty)) {
722 Some(it) => it,
723 None => self.data().type_refs.intern(TypeRef::Error),
724 }
717 } 725 }
718 726
719 /// Forces the visibility `vis` to be used for all items lowered during execution of `f`. 727 /// Forces the visibility `vis` to be used for all items lowered during execution of `f`.