Skip to content

Commit 0d8f633

Browse files
committed
Auto merge of #157275 - RalfJung:interpret-layout-cache, r=<try>
interpret: add per-interpreter layout cache
2 parents c0bb140 + cee454a commit 0d8f633

2 files changed

Lines changed: 29 additions & 28 deletions

File tree

compiler/rustc_const_eval/src/interpret/eval_context.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
use std::cell::RefCell;
2+
use std::collections::hash_map::Entry;
3+
14
use either::{Left, Right};
25
use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
6+
use rustc_data_structures::fx::FxHashMap;
37
use rustc_hir::def_id::DefId;
48
use rustc_hir::limit::Limit;
59
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
@@ -39,6 +43,9 @@ pub struct InterpCx<'tcx, M: Machine<'tcx>> {
3943
/// polymorphic context. This always uses `ty::TypingMode::PostAnalysis`.
4044
pub(super) typing_env: ty::TypingEnv<'tcx>,
4145

46+
/// The query cache is slow so we have our own cache in front of it.
47+
pub(super) layout_cache: RefCell<FxHashMap<Ty<'tcx>, rustc_abi::Layout<'tcx>>>,
48+
4249
/// The virtual memory system.
4350
pub memory: Memory<'tcx, M>,
4451

@@ -131,10 +138,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
131138
/// This inherent method takes priority over the trait method with the same name in LayoutOf,
132139
/// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span.
133140
/// See [LayoutOf::layout_of] for the original documentation.
134-
#[inline(always)]
141+
#[inline]
135142
pub fn layout_of(&self, ty: Ty<'tcx>) -> Result<TyAndLayout<'tcx>, InterpErrorKind<'tcx>> {
136-
let _trace = enter_trace_span!(M, layouting::layout_of, ty = ?ty.kind());
137-
LayoutOf::layout_of(self, ty)
143+
match self.layout_cache.borrow_mut().entry(ty) {
144+
Entry::Occupied(occupied_entry) => {
145+
Ok(TyAndLayout { ty, layout: *occupied_entry.get() })
146+
}
147+
Entry::Vacant(vacant_entry) => {
148+
let _trace = enter_trace_span!(M, layouting::layout_of, ty = ?ty.kind());
149+
let layout = LayoutOf::layout_of(self, ty)?;
150+
vacant_entry.insert(layout.layout);
151+
Ok(layout)
152+
}
153+
}
138154
}
139155

140156
/// This inherent method takes priority over the trait method with the same name in FnAbiOf,
@@ -258,6 +274,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
258274
machine,
259275
tcx: tcx.at(root_span),
260276
typing_env,
277+
layout_cache: RefCell::new(FxHashMap::default()),
261278
memory: Memory::new(),
262279
recursion_limit: tcx.recursion_limit(),
263280
}

compiler/rustc_const_eval/src/interpret/stack.rs

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! Manages the low-level pushing and popping of stack frames and the (de)allocation of local variables.
22
//! For handling of argument passing and return values, see the `call` module.
3-
use std::cell::Cell;
43
use std::{fmt, mem};
54

65
use either::{Either, Left, Right};
@@ -90,7 +89,7 @@ pub struct Frame<'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
9089
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
9190
///
9291
/// Do *not* access this directly; always go through the machine hook!
93-
pub locals: IndexVec<mir::Local, LocalState<'tcx, Prov>>,
92+
pub locals: IndexVec<mir::Local, LocalState<Prov>>,
9493

9594
/// The complete variable argument list of this frame. Its elements must be dropped when the
9695
/// frame is popped.
@@ -129,19 +128,13 @@ pub enum ReturnContinuation {
129128

130129
/// State of a local variable including a memoized layout
131130
#[derive(Clone)]
132-
pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
131+
pub struct LocalState<Prov: Provenance = CtfeProvenance> {
133132
value: LocalValue<Prov>,
134-
/// Don't modify if `Some`, this is only used to prevent computing the layout twice.
135-
/// Avoids computing the layout of locals that are never actually initialized.
136-
layout: Cell<Option<TyAndLayout<'tcx>>>,
137133
}
138134

139-
impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> {
135+
impl<Prov: Provenance> std::fmt::Debug for LocalState<Prov> {
140136
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141-
f.debug_struct("LocalState")
142-
.field("value", &self.value)
143-
.field("ty", &self.layout.get().map(|l| l.ty))
144-
.finish()
137+
f.debug_struct("LocalState").field("value", &self.value).finish()
145138
}
146139
}
147140

@@ -161,7 +154,7 @@ pub(super) enum LocalValue<Prov: Provenance = CtfeProvenance> {
161154
Live(Operand<Prov>),
162155
}
163156

164-
impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
157+
impl<'tcx, Prov: Provenance> LocalState<Prov> {
165158
pub fn make_live_uninit(&mut self) {
166159
self.value = LocalValue::Live(Operand::Immediate(Immediate::Uninit));
167160
}
@@ -377,7 +370,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
377370

378371
// First push a stack frame so we have access to `instantiate_from_current_frame` and other
379372
// `self.frame()`-based functions.
380-
let dead_local = LocalState { value: LocalValue::Dead, layout: Cell::new(None) };
373+
let dead_local = LocalState { value: LocalValue::Dead };
381374
let locals = IndexVec::from_elem(dead_local, &body.local_decls);
382375
let pre_frame = Frame {
383376
body,
@@ -613,21 +606,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
613606
local: mir::Local,
614607
layout: Option<TyAndLayout<'tcx>>,
615608
) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
616-
let state = &frame.locals[local];
617-
if let Some(layout) = state.layout.get() {
618-
return interp_ok(layout);
619-
}
620-
621-
let layout = from_known_layout(self.tcx, self.typing_env, layout, || {
609+
from_known_layout(self.tcx, self.typing_env, layout, || {
622610
let local_ty = frame.body.local_decls[local].ty;
623611
let local_ty =
624612
self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
625613
self.layout_of(local_ty).into()
626-
})?;
627-
628-
// Layouts of locals are requested a lot, so we cache them.
629-
state.layout.set(Some(layout));
630-
interp_ok(layout)
614+
})
631615
}
632616
}
633617

@@ -683,7 +667,7 @@ impl<'a, 'tcx: 'a, M: Machine<'tcx>> InterpCx<'tcx, M> {
683667
}
684668
}
685669

686-
impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
670+
impl<Prov: Provenance> LocalState<Prov> {
687671
pub(super) fn print(
688672
&self,
689673
allocs: &mut Vec<Option<AllocId>>,

0 commit comments

Comments
 (0)