Skip to content

Commit cc84819

Browse files
committed
Auto merge of #130148 - RalfJung:interpret-get_ptr_alloc_mut, r=<try>
interpret: get_ptr_alloc_mut: lookup allocation only once I don't think this will make a big perf difference, but it makes this function symmetric with `get_ptr_alloc` -- and it's always nice to successfully solve a borrow checker puzzle like this. ;)
2 parents 263a3ae + 4e8ddbd commit cc84819

File tree

1 file changed

+39
-23
lines changed
  • compiler/rustc_const_eval/src/interpret

1 file changed

+39
-23
lines changed

compiler/rustc_const_eval/src/interpret/memory.rs

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! short-circuiting the empty case!
88
99
use std::assert_matches::assert_matches;
10-
use std::borrow::Cow;
10+
use std::borrow::{Borrow, Cow};
1111
use std::cell::Cell;
1212
use std::collections::VecDeque;
1313
use std::{fmt, ptr};
@@ -387,12 +387,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
387387
size: Size,
388388
) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> {
389389
let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
390-
self.check_and_deref_ptr(
390+
Self::check_and_deref_ptr(
391+
self,
391392
ptr,
392393
size,
393394
CheckInAllocMsg::MemoryAccessTest,
394-
|alloc_id, offset, prov| {
395-
let (size, align) = self
395+
|this, alloc_id, offset, prov| {
396+
let (size, align) = this
396397
.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?;
397398
Ok((size, align, (alloc_id, offset, prov)))
398399
},
@@ -409,8 +410,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
409410
msg: CheckInAllocMsg,
410411
) -> InterpResult<'tcx> {
411412
let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
412-
self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| {
413-
let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
413+
Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| {
414+
let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?;
414415
Ok((size, align, ()))
415416
})?;
416417
Ok(())
@@ -425,8 +426,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
425426
size: i64,
426427
msg: CheckInAllocMsg,
427428
) -> InterpResult<'tcx> {
428-
self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| {
429-
let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
429+
Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| {
430+
let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?;
430431
Ok((size, align, ()))
431432
})?;
432433
Ok(())
@@ -440,12 +441,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
440441
/// `alloc_size` will only get called for non-zero-sized accesses.
441442
///
442443
/// Returns `None` if and only if the size is 0.
443-
fn check_and_deref_ptr<T>(
444-
&self,
444+
fn check_and_deref_ptr<T, R: Borrow<Self>>(
445+
this: R,
445446
ptr: Pointer<Option<M::Provenance>>,
446447
size: i64,
447448
msg: CheckInAllocMsg,
448449
alloc_size: impl FnOnce(
450+
R,
449451
AllocId,
450452
Size,
451453
M::ProvenanceExtra,
@@ -456,13 +458,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
456458
return Ok(None);
457459
}
458460

459-
Ok(match self.ptr_try_get_alloc_id(ptr, size) {
461+
Ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) {
460462
Err(addr) => {
461463
// We couldn't get a proper allocation.
462464
throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg });
463465
}
464466
Ok((alloc_id, offset, prov)) => {
465-
let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?;
467+
let tcx = this.borrow().tcx;
468+
let (alloc_size, _alloc_align, ret_val) = alloc_size(this, alloc_id, offset, prov)?;
466469
let offset = offset.bytes();
467470
// Compute absolute begin and end of the range.
468471
let (begin, end) = if size >= 0 {
@@ -476,7 +479,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
476479
throw_ub!(PointerOutOfBounds {
477480
alloc_id,
478481
alloc_size,
479-
ptr_offset: self.sign_extend_to_target_isize(offset),
482+
ptr_offset: tcx.sign_extend_to_target_isize(offset),
480483
inbounds_size: size,
481484
msg,
482485
})
@@ -670,12 +673,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
670673
) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
671674
{
672675
let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
673-
let ptr_and_alloc = self.check_and_deref_ptr(
676+
let ptr_and_alloc = Self::check_and_deref_ptr(
677+
self,
674678
ptr,
675679
size_i64,
676680
CheckInAllocMsg::MemoryAccessTest,
677-
|alloc_id, offset, prov| {
678-
let alloc = self.get_alloc_raw(alloc_id)?;
681+
|this, alloc_id, offset, prov| {
682+
let alloc = this.get_alloc_raw(alloc_id)?;
679683
Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc)))
680684
},
681685
)?;
@@ -727,7 +731,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
727731
// We have "NLL problem case #3" here, which cannot be worked around without loss of
728732
// efficiency even for the common case where the key is in the map.
729733
// <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions>
730-
// (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`.)
734+
// (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`, and that boils down to
735+
// Miri's `adjust_alloc_root_pointer` needing to look up the size of the allocation.
736+
// It could be avoided with a totally separate codepath in Miri for handling the absolute address
737+
// of global allocations, but that's not worth it.)
731738
if self.memory.alloc_map.get_mut(id).is_none() {
732739
// Slow path.
733740
// Allocation not found locally, go look global.
@@ -763,12 +770,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
763770
size: Size,
764771
) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
765772
{
766-
let parts = self.get_ptr_access(ptr, size)?;
767-
if let Some((alloc_id, offset, prov)) = parts {
768-
let tcx = self.tcx;
769-
// FIXME: can we somehow avoid looking up the allocation twice here?
770-
// We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
771-
let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?;
773+
let tcx = self.tcx;
774+
775+
let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
776+
let ptr_and_alloc = Self::check_and_deref_ptr(
777+
self,
778+
ptr,
779+
size_i64,
780+
CheckInAllocMsg::MemoryAccessTest,
781+
|this, alloc_id, offset, prov| {
782+
let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?;
783+
Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine)))
784+
},
785+
)?;
786+
787+
if let Some((alloc_id, offset, prov, alloc, machine)) = ptr_and_alloc {
772788
let range = alloc_range(offset, size);
773789
M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?;
774790
Ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id }))

0 commit comments

Comments
 (0)