Skip to content

Commit e2b71ad

Browse files
committed
Auto merge of #158604 - LorrensP-2158466:less-alloc-during-res, r=petrochenkov
resolve: no allocation in `resolve_ident_in(_local)_module_*` Somewhat of a follow up of #158207 and #158035. Remove the `or_default` call of `NameResolutions` which does an arena allocation. Prep work for parallel import resolution. - cycle detection now works on `module` and `bindingkey` instead of the `NameResolution`. This should have no impact as `NameResolutions` are found by that pair. - Now that we get an `Option<NameResolution>` the logic changed a bit to work with `None`. Did this by following the logic of the functions to see what would happen with a completely empty resolution (`or_default`). r? @petrochenkov
2 parents 7c5dac9 + d737d29 commit e2b71ad

2 files changed

Lines changed: 44 additions & 38 deletions

File tree

compiler/rustc_resolve/src/ident.rs

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,10 +1148,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
11481148
ignore_import: Option<Import<'ra>>,
11491149
) -> Result<Decl<'ra>, ControlFlow<Determinacy, Determinacy>> {
11501150
let key = BindingKey::new(ident, ns);
1151-
let resolution_ref = self.resolution_or_default(module.to_module(), key, orig_ident_span);
1152-
let resolution = resolution_ref.borrow();
1151+
let resolution = self.resolution(module.to_module(), key);
11531152

1154-
let binding = resolution.non_glob_decl.filter(|b| Some(*b) != ignore_decl);
1153+
let binding =
1154+
resolution.as_ref().and_then(|r| r.non_glob_decl).filter(|b| Some(*b) != ignore_decl);
11551155

11561156
if let Some(finalize) = finalize {
11571157
return self.get_mut().finalize_module_binding(
@@ -1170,21 +1170,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
11701170
return if accessible { Ok(binding) } else { Err(ControlFlow::Break(Determined)) };
11711171
}
11721172

1173-
// We need to detect resolution cycles to avoid infinite recursion. The guard ensures
1174-
// the resolution is removed when this resolve call ends.
1175-
let _cycle_guard = cycle_detection::enter_cycle_detector(resolution_ref)
1176-
.map_err(|_| ControlFlow::Continue(Determined))?;
1173+
if let Some(resolution) = resolution {
1174+
// We need to detect resolution cycles to avoid infinite recursion. The guard ensures
1175+
// the resolution is removed when this resolve call ends.
1176+
let _cycle_guard = cycle_detection::enter_cycle_detector(module, key)
1177+
.map_err(|_| ControlFlow::Continue(Determined))?;
11771178

1178-
// Check if one of single imports can still define the name, block if it can.
1179-
if self.reborrow().single_import_can_define_name(
1180-
&resolution,
1181-
None,
1182-
ns,
1183-
ignore_import,
1184-
ignore_decl,
1185-
parent_scope,
1186-
) {
1187-
return Err(ControlFlow::Break(Undetermined));
1179+
// Check if one of single imports can still define the name, block if it can.
1180+
if self.reborrow().single_import_can_define_name(
1181+
&resolution,
1182+
None,
1183+
ns,
1184+
ignore_import,
1185+
ignore_decl,
1186+
parent_scope,
1187+
) {
1188+
return Err(ControlFlow::Break(Undetermined));
1189+
}
11881190
}
11891191

11901192
// Check if one of unexpanded macros can still define the name.
@@ -1210,10 +1212,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
12101212
ignore_import: Option<Import<'ra>>,
12111213
) -> Result<Decl<'ra>, ControlFlow<Determinacy, Determinacy>> {
12121214
let key = BindingKey::new(ident, ns);
1213-
let resolution_ref = self.resolution_or_default(module.to_module(), key, orig_ident_span);
1214-
let resolution = resolution_ref.borrow();
1215+
let resolution = self.resolution(module.to_module(), key);
12151216

1216-
let binding = resolution.glob_decl.filter(|b| Some(*b) != ignore_decl);
1217+
let binding =
1218+
resolution.as_ref().and_then(|r| r.glob_decl).filter(|b| Some(*b) != ignore_decl);
12171219

12181220
if let Some(finalize) = finalize {
12191221
return self.get_mut().finalize_module_binding(
@@ -1228,20 +1230,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
12281230

12291231
// We need to detect resolution cycles to avoid infinite recursion. The guard ensures
12301232
// the resolution is removed when this resolve call ends.
1231-
let _cycle_guard = cycle_detection::enter_cycle_detector(resolution_ref)
1233+
let _cycle_guard = cycle_detection::enter_cycle_detector(module, key)
12321234
.map_err(|_| ControlFlow::Continue(Determined))?;
12331235

12341236
// Check if one of single imports can still define the name,
12351237
// if it can then our result is not determined and can be invalidated.
1236-
if self.reborrow().single_import_can_define_name(
1237-
&resolution,
1238-
binding,
1239-
ns,
1240-
ignore_import,
1241-
ignore_decl,
1242-
parent_scope,
1243-
) {
1244-
return Err(ControlFlow::Break(Undetermined));
1238+
if let Some(resolution) = resolution {
1239+
if self.reborrow().single_import_can_define_name(
1240+
&resolution,
1241+
binding,
1242+
ns,
1243+
ignore_import,
1244+
ignore_decl,
1245+
parent_scope,
1246+
) {
1247+
return Err(ControlFlow::Break(Undetermined));
1248+
}
12451249
}
12461250

12471251
// So we have a resolution that's from a glob import. This resolution is determined

compiler/rustc_resolve/src/imports.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -326,23 +326,23 @@ impl<'ra> NameResolution<'ra> {
326326
pub(crate) mod cycle_detection {
327327
use std::ptr;
328328

329-
use crate::CacheRefCell;
330-
use crate::imports::NameResolutionRef;
329+
use crate::{BindingKey, CacheRefCell, LocalModule};
331330

332331
thread_local!(
333332
/// During import resolution, recursive imports can form cycles.
334333
/// This set stores the active resolution stack for the current thread.
335-
/// So it's essentially a recursion stack.
334+
/// By keeping track of the module and `BindingKey` pair that identifies
335+
/// the specific resolution.
336336
///
337-
/// The key is the interned address of a `RefCell<NameResolution<'ra>>` allocated
337+
/// The pointer is the interned address of a `Interned<'ra, ModuleData>` allocated
338338
/// in the `Resolver Arenas` (lifetime `'ra`), it is thus stable and allows casting
339339
/// to a `*const ()` for comparison. This is done because we can't use lifetimes
340340
/// other than `'static` in thread local storage.
341-
static ACTIVE_RESOLUTIONS: CacheRefCell<Vec<*const ()>> = Default::default();
341+
static ACTIVE_RESOLUTIONS: CacheRefCell<Vec<(*const (), BindingKey)>> = Default::default();
342342
);
343343

344344
pub(crate) struct ActiveResolutionGuard {
345-
key: *const (),
345+
key: (*const (), BindingKey),
346346
}
347347

348348
impl Drop for ActiveResolutionGuard {
@@ -360,9 +360,11 @@ pub(crate) mod cycle_detection {
360360
/// Returns `Err(())` if a cycle is detected, otherwise this returns a
361361
/// guard that will remove the resolution when dropped.
362362
pub(crate) fn enter_cycle_detector<'ra>(
363-
resolution: NameResolutionRef<'ra>,
363+
module: LocalModule<'ra>,
364+
binding_key: BindingKey,
364365
) -> Result<ActiveResolutionGuard, ()> {
365-
let key = ptr::from_ref(resolution.0).cast::<()>();
366+
let module_key = ptr::from_ref(module.0.0).cast();
367+
let key = (module_key, binding_key);
366368
ACTIVE_RESOLUTIONS.with_borrow_mut(|ar| {
367369
if ar.contains(&key) {
368370
return Err(());

0 commit comments

Comments
 (0)