Skip to content

Commit e35d56b

Browse files
committed
Avoid copying memory representation of undef data
During MIR interpretation it may happen that a place containing uninitialized bytes is copied. This would read the current representation of these bytes and write it to the destination even though they must, by definition, not matter to the execution. This elides that representation change when no bytes are defined in such a copy, saving some cpu cycles. In such a case, the memory of the target allocation is not touched at all which also means that sometimes no physical page backing the memory allocation of the representation needs to be provided by the OS at all, reducing memory pressure on the system.
1 parent 2da942f commit e35d56b

File tree

2 files changed

+26
-23
lines changed

2 files changed

+26
-23
lines changed

src/librustc/mir/interpret/allocation.rs

+6
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,12 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
695695
}
696696
}
697697

698+
impl AllocationDefinedness {
699+
pub fn all_bytes_undef(&self) -> bool {
700+
self.initial == false && self.ranges.len() == 1
701+
}
702+
}
703+
698704
/// Relocations.
699705
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
700706
pub struct Relocations<Tag = (), Id = AllocId>(SortedMap<Size, (Tag, Id)>);

src/librustc_mir/interpret/memory.rs

+20-23
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,22 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
855855
let relocations = self.get_raw(src.alloc_id)?
856856
.prepare_relocation_copy(self, src, size, dest, length);
857857

858+
// Prepare a copy of the undef mask.
859+
let compressed = self.get_raw(src.alloc_id)?.compress_undef_range(src, size);
860+
861+
if compressed.all_bytes_undef() {
862+
// Fast path: If all bytes are `undef` then there is nothing to copy. The target range
863+
// is marked as undef but we otherwise omit changing the byte representation which may
864+
// be arbitrary for undef bytes.
865+
// This also avoids writing to the target bytes so that the backing allocation is never
866+
// touched if the bytes stay undef for the whole interpreter execution. On contemporary
867+
// operating system this can avoid physically allocating the page.
868+
let dest_alloc = self.get_raw_mut(dest.alloc_id)?;
869+
dest_alloc.mark_definedness(dest, size * length, false);
870+
dest_alloc.mark_relocation_range(relocations);
871+
return Ok(());
872+
}
873+
858874
let tcx = self.tcx.tcx;
859875

860876
// This checks relocation edges on the src.
@@ -897,8 +913,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
897913
}
898914
}
899915

900-
// copy definedness to the destination
901-
self.copy_undef_mask(src, dest, size, length)?;
916+
// now copy over the undef data
917+
self.get_raw_mut(dest.alloc_id)?
918+
.mark_compressed_undef_range(&compressed, dest, size, length);
919+
902920
// copy the relocations to the destination
903921
self.get_raw_mut(dest.alloc_id)?.mark_relocation_range(relocations);
904922

@@ -908,27 +926,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
908926

909927
/// Undefined bytes
910928
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
911-
// FIXME: Add a fast version for the common, nonoverlapping case
912-
fn copy_undef_mask(
913-
&mut self,
914-
src: Pointer<M::PointerTag>,
915-
dest: Pointer<M::PointerTag>,
916-
size: Size,
917-
repeat: u64,
918-
) -> InterpResult<'tcx> {
919-
// The bits have to be saved locally before writing to dest in case src and dest overlap.
920-
assert_eq!(size.bytes() as usize as u64, size.bytes());
921-
922-
let src_alloc = self.get_raw(src.alloc_id)?;
923-
let compressed = src_alloc.compress_undef_range(src, size);
924-
925-
// now fill in all the data
926-
let dest_allocation = self.get_raw_mut(dest.alloc_id)?;
927-
dest_allocation.mark_compressed_undef_range(&compressed, dest, size, repeat);
928-
929-
Ok(())
930-
}
931-
932929
pub fn force_ptr(
933930
&self,
934931
scalar: Scalar<M::PointerTag>,

0 commit comments

Comments
 (0)