diff options
| author | SpecificProtagonist <specificprotagonist@posteo.org> | 2025-01-25 00:54:51 +0100 | 
|---|---|---|
| committer | SpecificProtagonist <specificprotagonist@posteo.org> | 2025-01-28 12:50:02 +0100 | 
| commit | eee9df43e69e9841aaaa9bd4eae9f600a81f20b1 (patch) | |
| tree | ecb48bd31a0ad47f79c23f0c8669ec0f991c1b70 /compiler | |
| parent | 8231e8599e238ff4e717639bd68c6abb8579fe8d (diff) | |
| download | rust-eee9df43e69e9841aaaa9bd4eae9f600a81f20b1.tar.gz rust-eee9df43e69e9841aaaa9bd4eae9f600a81f20b1.zip  | |
miri: optimize zeroed alloc
Co-authored-by: Ralf Jung <post@ralfj.de>
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_const_eval/src/const_eval/machine.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/memory.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/place.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/util.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/allocation.rs | 26 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/mod.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/vtable.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_smir/src/rustc_smir/alloc.rs | 12 | 
8 files changed, 59 insertions, 30 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index cfdfbdb7880..6a339d69542 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -21,9 +21,10 @@ use super::error::*; use crate::errors::{LongRunning, LongRunningWarn}; use crate::fluent_generated as fluent; use crate::interpret::{ - self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, - InterpCx, InterpResult, MPlaceTy, OpTy, RangeSet, Scalar, compile_time_machine, interp_ok, - throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, + self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, + GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, RangeSet, Scalar, + compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, + throw_unsup, throw_unsup_format, }; /// When hitting this many interpreted terminators we emit a deny by default lint @@ -420,6 +421,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { Size::from_bytes(size), align, interpret::MemoryKind::Machine(MemoryKind::Heap), + AllocInit::Uninit, )?; ecx.write_pointer(ptr, dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 2772c94d52b..1b8a222e9ea 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -20,10 +20,10 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use tracing::{debug, instrument, trace}; use super::{ - AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg, - CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer, - PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub, - throw_ub_custom, throw_unsup, throw_unsup_format, + AllocBytes, AllocId, AllocInit, AllocMap, AllocRange, Allocation, CheckAlignMsg, + CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, + Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, + err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; use crate::fluent_generated as fluent; @@ -230,11 +230,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { size: Size, align: Align, kind: MemoryKind<M::MemoryKind>, + init: AllocInit, ) -> InterpResult<'tcx, Pointer<M::Provenance>> { let alloc = if M::PANIC_ON_ALLOC_FAIL { - Allocation::uninit(size, align) + Allocation::new(size, align, init) } else { - Allocation::try_uninit(size, align)? + Allocation::try_new(size, align, init)? }; self.insert_allocation(alloc, kind) } @@ -270,6 +271,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind)) } + /// If this grows the allocation, `init_growth` determines + /// whether the additional space will be initialized. pub fn reallocate_ptr( &mut self, ptr: Pointer<Option<M::Provenance>>, @@ -277,6 +280,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { new_size: Size, new_align: Align, kind: MemoryKind<M::MemoryKind>, + init_growth: AllocInit, ) -> InterpResult<'tcx, Pointer<M::Provenance>> { let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr, 0)?; if offset.bytes() != 0 { @@ -289,7 +293,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc". // This happens so rarely, the perf advantage is outweighed by the maintenance cost. - let new_ptr = self.allocate_ptr(new_size, new_align, kind)?; + // If requested, we zero-init the entire allocation, to ensure that a growing + // allocation has its new bytes properly set. For the part that is copied, + // `mem_copy` below will de-initialize things as necessary. + let new_ptr = self.allocate_ptr(new_size, new_align, kind, init_growth)?; let old_size = match old_size_and_align { Some((size, _align)) => size, None => self.get_alloc_raw(alloc_id)?.size(), diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index c97922ac132..f5d3de7b1b2 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -12,9 +12,9 @@ use rustc_middle::{bug, mir, span_bug}; use tracing::{instrument, trace}; use super::{ - AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult, - Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance, - Scalar, alloc_range, interp_ok, mir_assign_valid_types, + AllocInit, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, + InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, + Projectable, Provenance, Scalar, alloc_range, interp_ok, mir_assign_valid_types, }; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] @@ -983,7 +983,7 @@ where let Some((size, align)) = self.size_and_align_of(&meta, &layout)? else { span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known") }; - let ptr = self.allocate_ptr(size, align, kind)?; + let ptr = self.allocate_ptr(size, align, kind, AllocInit::Uninit)?; interp_ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false)) } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index ecb7c3fc93c..eb98e3b5380 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -2,7 +2,7 @@ use std::ops::ControlFlow; use rustc_hir::def_id::LocalDefId; use rustc_middle::mir; -use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer}; +use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -76,7 +76,7 @@ pub(crate) fn create_static_alloc<'tcx>( static_def_id: LocalDefId, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - let alloc = Allocation::try_uninit(layout.size, layout.align.abi)?; + let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit)?; let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into()); assert_eq!(ecx.machine.static_root_ids, None); ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 1b07846e0cf..2e4d258ffff 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -270,6 +270,12 @@ impl AllocRange { } } +/// Whether a new allocation should be initialized with zero-bytes. +pub enum AllocInit { + Uninit, + Zero, +} + // The constructors are all without extra; the extra gets added by a machine hook later. impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { /// Creates an allocation initialized by the given bytes @@ -294,7 +300,12 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { Allocation::from_bytes(slice, Align::ONE, Mutability::Not) } - fn uninit_inner<R>(size: Size, align: Align, fail: impl FnOnce() -> R) -> Result<Self, R> { + fn new_inner<R>( + size: Size, + align: Align, + init: AllocInit, + fail: impl FnOnce() -> R, + ) -> Result<Self, R> { // We raise an error if we cannot create the allocation on the host. // This results in an error that can happen non-deterministically, since the memory // available to the compiler can change between runs. Normally queries are always @@ -306,7 +317,10 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { Ok(Allocation { bytes, provenance: ProvenanceMap::new(), - init_mask: InitMask::new(size, false), + init_mask: InitMask::new(size, match init { + AllocInit::Uninit => false, + AllocInit::Zero => true, + }), align, mutability: Mutability::Mut, extra: (), @@ -315,8 +329,8 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { /// Try to create an Allocation of `size` bytes, failing if there is not enough memory /// available to the compiler to do so. - pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> { - Self::uninit_inner(size, align, || { + pub fn try_new<'tcx>(size: Size, align: Align, init: AllocInit) -> InterpResult<'tcx, Self> { + Self::new_inner(size, align, init, || { ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation")); InterpErrorKind::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) }) @@ -328,8 +342,8 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { /// /// Example use case: To obtain an Allocation filled with specific data, /// first call this function and then call write_scalar to fill in the right data. - pub fn uninit(size: Size, align: Align) -> Self { - match Self::uninit_inner(size, align, || { + pub fn new(size: Size, align: Align, init: AllocInit) -> Self { + match Self::new_inner(size, align, init, || { panic!( "interpreter ran out of memory: cannot create allocation of {} bytes", size.bytes() diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index b88137544bc..f4f9f221a75 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -30,8 +30,8 @@ pub use { }; pub use self::allocation::{ - AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk, - InitChunkIter, alloc_range, + AllocBytes, AllocError, AllocInit, AllocRange, AllocResult, Allocation, ConstAllocation, + InitChunk, InitChunkIter, alloc_range, }; pub use self::error::{ BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult, diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 23e2e8ad3d3..455bd16ff8c 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -4,7 +4,9 @@ use rustc_ast::Mutability; use rustc_macros::HashStable; use rustc_type_ir::elaborate; -use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range}; +use crate::mir::interpret::{ + AllocId, AllocInit, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range, +}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; #[derive(Clone, Copy, PartialEq, HashStable)] @@ -108,7 +110,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let ptr_align = tcx.data_layout.pointer_align.abi; let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap(); - let mut vtable = Allocation::uninit(vtable_size, ptr_align); + let mut vtable = Allocation::new(vtable_size, ptr_align, AllocInit::Uninit); // No need to do any alignment checks on the memory accesses below, because we know the // allocation is correctly aligned as we created it above. Also we're only offsetting by diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs index 4e8db6096d4..52c5b425c14 100644 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs @@ -1,6 +1,6 @@ use rustc_abi::{Align, Size}; use rustc_middle::mir::ConstValue; -use rustc_middle::mir::interpret::{AllocRange, Pointer, alloc_range}; +use rustc_middle::mir::interpret::{AllocInit, AllocRange, Pointer, alloc_range}; use stable_mir::Error; use stable_mir::mir::Mutability; use stable_mir::ty::{Allocation, ProvenanceMap}; @@ -44,7 +44,8 @@ pub(crate) fn try_new_allocation<'tcx>( .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty)) .map_err(|e| e.stable(tables))? .align; - let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi); + let mut allocation = + rustc_middle::mir::interpret::Allocation::new(size, align.abi, AllocInit::Uninit); allocation .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar) .map_err(|e| e.stable(tables))?; @@ -68,8 +69,11 @@ pub(crate) fn try_new_allocation<'tcx>( .tcx .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty)) .map_err(|e| e.stable(tables))?; - let mut allocation = - rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi); + let mut allocation = rustc_middle::mir::interpret::Allocation::new( + layout.size, + layout.align.abi, + AllocInit::Uninit, + ); allocation .write_scalar( &tables.tcx,  | 
