@@ -296,6 +296,19 @@ impl<'tcx> Stack {
296296 return Ok ( ( ) ) ;
297297 }
298298
299+ // We store tags twice, once in global.protected_tags and once in each call frame.
300+ // We do this because consulting a single global set in this function is faster
301+ // than attempting to search all call frames in the program for the `FrameExtra`
302+ // (if any) which is protecting the popped tag.
303+ //
304+ // This duplication trades off making `end_call` slower to make this function faster. This
305+ // trade-off is profitable in practice for a combination of two reasons.
306+ // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s.
307+ // Therefore, adding overhead in function call/return is profitable even if it only
308+ // saves a little work in this function.
309+ // 2. Most frames protect only one or two tags. So this duplicative global turns a search
310+ // which ends up about linear in the number of protected tags in the program into a
311+ // constant time check (and a slow linear, because the tags in the frames aren't contiguous).
299312 if global. protected_tags . contains ( & item. tag ( ) ) {
300313 return Err ( dcx. protector_error ( item) . into ( ) ) ;
301314 }
@@ -622,6 +635,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
622635 protect : bool ,
623636 ) -> InterpResult < ' tcx , Option < AllocId > > {
624637 let this = self . eval_context_mut ( ) ;
638+ let current_span = this. machine . current_span ( * this. tcx ) ;
625639
626640 // It is crucial that this gets called on all code paths, to ensure we track tag creation.
627641 let log_creation = |this : & MiriEvalContext < ' mir , ' tcx > ,
@@ -674,8 +688,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
674688 Ok ( ( ) )
675689 } ;
676690
677- let current_span = this. machine . current_span ( * this. tcx ) ;
678-
679691 if size == Size :: ZERO {
680692 trace ! (
681693 "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})" ,
@@ -726,19 +738,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
726738 ) ;
727739
728740 if protect {
729- // We store tags twice, once in global.protected_tags and once in each call frame.
730- // We do this because consulting a single global set in this function is faster
731- // than attempting to search all call frames in the program for the `FrameExtra`
732- // (if any) which is protecting the popped tag.
733- //
734- // This duplication trades off making `end_call` slower to make this function faster. This
735- // trade-off is profitable in practice for a combination of two reasons.
736- // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s.
737- // Therefore, adding overhead to in function call/return is profitable even if it only
738- // saves a little work in this function.
739- // 2. Most frames protect only one or two tags. So this duplicative global turns a search
740- // which ends up about linear in the number of protected tags in the program into a
741- // constant time check (and a slow linear, because the tags in the frames aren't contiguous).
741+ // See comment in `Stack::item_popped` for why we store the tag twice.
742742 this. frame_mut ( ) . extra . stacked_borrows . as_mut ( ) . unwrap ( ) . protected_tags . push ( new_tag) ;
743743 this. machine . stacked_borrows . as_mut ( ) . unwrap ( ) . get_mut ( ) . protected_tags . insert ( new_tag) ;
744744 }
@@ -818,7 +818,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
818818 let range = alloc_range ( base_offset, size) ;
819819 let mut global = machine. stacked_borrows . as_ref ( ) . unwrap ( ) . borrow_mut ( ) ;
820820 let dcx = DiagnosticCxBuilder :: retag (
821- machine. current_span ( tcx) ,
821+ machine. current_span ( tcx) , // `get_alloc_extra_mut` invalidated our old `current_span`
822822 & machine. threads ,
823823 retag_cause,
824824 new_tag,
0 commit comments