Skip to content

Commit 36b97cd

Browse files
committed
Factor out common top-level code from escape-to-raw and retag
1 parent c54dcf5 commit 36b97cd

File tree

1 file changed

+50
-29
lines changed

1 file changed

+50
-29
lines changed

src/stacked_borrows.rs

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,9 @@ impl<'tcx> Stacks {
303303
trace!("{} access of tag {:?}: {:?}, size {}",
304304
if is_write { "read" } else { "write" },
305305
ptr.tag, ptr, size.bytes());
306+
// Even reads can have a side-effect, by invalidating other references.
307+
// This is fundamentally necessary since `&mut` asserts that there
308+
// are no accesses through other references, not even reads.
306309
let mut stacks = self.stacks.borrow_mut();
307310
for stack in stacks.iter_mut(ptr.offset, size) {
308311
stack.access(ptr.tag, is_write)?;
@@ -311,6 +314,7 @@ impl<'tcx> Stacks {
311314
}
312315

313316
/// Reborrow the given pointer to the new tag for the given kind of reference.
317+
/// This works on `&self` because we might encounter references to constant memory.
314318
fn reborrow(
315319
&self,
316320
ptr: Pointer<Borrow>,
@@ -414,8 +418,16 @@ pub trait EvalContextExt<'tcx> {
414418
kind: MemoryKind<MiriMemoryKind>,
415419
) -> Borrow;
416420

417-
/// Retag an indidual pointer, returning the retagged version.
421+
/// Reborrow the given place, returning the newly tagged ptr to it.
418422
fn reborrow(
423+
&mut self,
424+
place: MPlaceTy<'tcx, Borrow>,
425+
size: Size,
426+
new_bor: Borrow
427+
) -> EvalResult<'tcx, Pointer<Borrow>>;
428+
429+
/// Retag an indidual pointer, returning the retagged version.
430+
fn retag_reference(
419431
&mut self,
420432
ptr: ImmTy<'tcx, Borrow>,
421433
mutbl: Mutability,
@@ -536,22 +548,46 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
536548
}
537549

538550
/// The given place may henceforth be accessed through raw pointers.
551+
#[inline(always)]
539552
fn escape_to_raw(
540553
&mut self,
541554
place: MPlaceTy<'tcx, Borrow>,
542555
size: Size,
543556
) -> EvalResult<'tcx> {
544-
trace!("escape_to_raw: {:?} is now accessible by raw pointers", *place);
545-
// Get the allocation
557+
self.reborrow(place, size, Borrow::default())?;
558+
Ok(())
559+
}
560+
561+
fn reborrow(
562+
&mut self,
563+
place: MPlaceTy<'tcx, Borrow>,
564+
size: Size,
565+
new_bor: Borrow
566+
) -> EvalResult<'tcx, Pointer<Borrow>> {
546567
let ptr = place.ptr.to_ptr()?;
547-
self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr
568+
let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor);
569+
trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}",
570+
ptr, place.layout.ty, new_bor);
571+
572+
// Get the allocation. It might not be mutable, so we cannot use `get_mut`.
573+
self.memory().check_bounds(ptr, size, false)?;
548574
let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!");
549-
// Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow
550-
// type here and that's also okay. Freezing does not matter here.
551-
alloc.extra.reborrow(ptr, size, Borrow::default(), RefKind::Raw)
575+
// Update the stacks.
576+
if let Borrow::Shr(Some(_)) = new_bor {
577+
// Reference that cares about freezing. We need a frozen-sensitive reborrow.
578+
self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| {
579+
let kind = if frozen { RefKind::Frozen } else { RefKind::Raw };
580+
alloc.extra.reborrow(cur_ptr, size, new_bor, kind)
581+
})?;
582+
} else {
583+
// Just treat this as one big chunk.
584+
let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw };
585+
alloc.extra.reborrow(ptr, size, new_bor, kind)?;
586+
}
587+
Ok(new_ptr)
552588
}
553589

554-
fn reborrow(
590+
fn retag_reference(
555591
&mut self,
556592
val: ImmTy<'tcx, Borrow>,
557593
mutbl: Mutability,
@@ -566,33 +602,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
566602
return Ok(*val);
567603
}
568604

569-
// Prepare to re-borrow this place.
570-
let ptr = place.ptr.to_ptr()?;
605+
// Compute new borrow.
571606
let time = self.machine.stacked_borrows.increment_clock();
572607
let new_bor = match mutbl {
573608
MutMutable => Borrow::Uniq(time),
574609
MutImmutable => Borrow::Shr(Some(time)),
575610
};
576-
trace!("reborrow: Creating new {:?} reference for {:?} (pointee {}): {:?}",
577-
mutbl, ptr, place.layout.ty, new_bor);
578611

579-
// Get the allocation. It might not be mutable, so we cannot use `get_mut`.
580-
self.memory().check_bounds(ptr, size, false)?;
581-
let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!");
582-
// Update the stacks.
583-
if mutbl == MutImmutable {
584-
// Shared reference. We need a frozen-sensitive reborrow.
585-
self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| {
586-
let kind = if frozen { RefKind::Frozen } else { RefKind::Raw };
587-
alloc.extra.reborrow(cur_ptr, size, new_bor, kind)
588-
})?;
589-
} else {
590-
// Mutable reference. Just treat this as one big chunk.
591-
alloc.extra.reborrow(ptr, size, new_bor, RefKind::Unique)?;
592-
}
612+
// Reborrow.
613+
let new_ptr = self.reborrow(place, size, new_bor)?;
593614

594615
// Return new ptr
595-
let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor);
596616
let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place };
597617
Ok(new_place.to_ref())
598618
}
@@ -611,8 +631,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
611631
ty::Ref(_, _, mutbl) => {
612632
// fast path
613633
let val = self.read_immediate(self.place_to_op(place)?)?;
614-
let val = self.reborrow(val, mutbl)?;
634+
let val = self.retag_reference(val, mutbl)?;
615635
self.write_immediate(val, place)?;
636+
return Ok(());
616637
}
617638
_ => {}, // handled with the general case below
618639
};
@@ -643,7 +664,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
643664
match place.layout.ty.sty {
644665
ty::Ref(_, _, mutbl) => {
645666
let val = self.ecx.read_immediate(place.into())?;
646-
let val = self.ecx.reborrow(val, mutbl)?;
667+
let val = self.ecx.retag_reference(val, mutbl)?;
647668
self.ecx.write_immediate(val, place.into())?;
648669
}
649670
_ => {}, // nothing to do

0 commit comments

Comments
 (0)