Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 97a0b2e

Browse files
committed
ctfe interning: don't walk allocations that don't need it
The interning of const allocations visits the mplace looking for references to intern. Walking big aggregates like big static arrays can be costly, so we only do it if the allocation we're interning contains references or interior mutability. Walking ZSTs was avoided before, and this optimization is now applied to cases where there are no references/relocations either.
1 parent 94e9374 commit 97a0b2e

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

compiler/rustc_const_eval/src/interpret/intern.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
168168
mplace: &MPlaceTy<'tcx>,
169169
fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
170170
) -> InterpResult<'tcx> {
171-
// ZSTs cannot contain pointers, so we can skip them.
172-
if mplace.layout.is_zst() {
171+
// We want to walk the aggregate to look for reference types to intern. While doing that we
172+
// also need to take special care of interior mutability.
173+
//
174+
// As an optimization, however, if the allocation does not contain any pointers: we don't
175+
// need to do the walk. It can be costly for big arrays for example (e.g. issue #93215).
176+
177+
let Some((size, align)) = self.ecx.size_and_align_of_mplace(&mplace)? else {
178+
// We could be dealing with an extern type here in the future, so we do the regular
179+
// walk.
180+
return self.walk_aggregate(mplace, fields);
181+
};
182+
183+
let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr, size, align)? else {
184+
// ZSTs cannot contain pointers, so we can skip them.
173185
return Ok(());
174-
}
186+
};
175187

176188
if let Some(def) = mplace.layout.ty.ty_adt_def() {
177189
if Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() {
@@ -186,6 +198,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
186198
}
187199
}
188200

201+
if !alloc.has_relocations() {
202+
// There are no refs or relocations in this allocation, we can skip the interning walk.
203+
return Ok(());
204+
}
205+
189206
self.walk_aggregate(mplace, fields)
190207
}
191208

compiler/rustc_const_eval/src/interpret/memory.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,11 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
942942
.check_bytes(&self.tcx, self.range.subrange(range), allow_uninit, allow_ptr)
943943
.map_err(|e| e.to_interp_error(self.alloc_id))?)
944944
}
945+
946+
/// Returns whether the allocation has relocations for the entire range of the `AllocRef`.
947+
pub(crate) fn has_relocations(&self) -> bool {
948+
!self.alloc.get_relocations(&self.tcx, self.range).is_empty()
949+
}
945950
}
946951

947952
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

0 commit comments

Comments
 (0)