diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-02-04 18:33:57 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-02-04 18:33:57 +0000 |
commit | 36191543a679d4e01c206d2e98a2d7ae170a25e2 (patch) | |
tree | 91431506bde2965c819030eea14433926b82310f /crates | |
parent | 663d404a4ee52cf96e0de793e45290be1a43dcb5 (diff) | |
parent | 003ee0086ae424ec43ad14cd90af9cd5809a93c8 (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]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir_def/src/adt.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/data.rs | 14 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 54 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 18 |
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)] | ||
287 | struct TypeRefStorage { | ||
288 | arena: Arena<Arc<TypeRef>>, | ||
289 | map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>, | ||
290 | } | ||
291 | |||
292 | impl 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)] |
283 | struct ItemTreeData { | 312 | struct 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 | ||
522 | impl 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 | |||
492 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | 530 | impl<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)] |
610 | pub struct Impl { | 648 | pub 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)] |
807 | pub struct Field { | 845 | pub 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`. |