@@ -296,6 +296,19 @@ impl<'tcx> Stack {
296
296
return Ok ( ( ) ) ;
297
297
}
298
298
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).
299
312
if global. protected_tags . contains ( & item. tag ( ) ) {
300
313
return Err ( dcx. protector_error ( item) . into ( ) ) ;
301
314
}
@@ -622,6 +635,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
622
635
protect : bool ,
623
636
) -> InterpResult < ' tcx , Option < AllocId > > {
624
637
let this = self . eval_context_mut ( ) ;
638
+ let current_span = this. machine . current_span ( * this. tcx ) ;
625
639
626
640
// It is crucial that this gets called on all code paths, to ensure we track tag creation.
627
641
let log_creation = |this : & MiriEvalContext < ' mir , ' tcx > ,
@@ -674,8 +688,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
674
688
Ok ( ( ) )
675
689
} ;
676
690
677
- let current_span = this. machine . current_span ( * this. tcx ) ;
678
-
679
691
if size == Size :: ZERO {
680
692
trace ! (
681
693
"reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})" ,
@@ -726,19 +738,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
726
738
) ;
727
739
728
740
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.
742
742
this. frame_mut ( ) . extra . stacked_borrows . as_mut ( ) . unwrap ( ) . protected_tags . push ( new_tag) ;
743
743
this. machine . stacked_borrows . as_mut ( ) . unwrap ( ) . get_mut ( ) . protected_tags . insert ( new_tag) ;
744
744
}
@@ -818,7 +818,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
818
818
let range = alloc_range ( base_offset, size) ;
819
819
let mut global = machine. stacked_borrows . as_ref ( ) . unwrap ( ) . borrow_mut ( ) ;
820
820
let dcx = DiagnosticCxBuilder :: retag (
821
- machine. current_span ( tcx) ,
821
+ machine. current_span ( tcx) , // `get_alloc_extra_mut` invalidated our old `current_span`
822
822
& machine. threads ,
823
823
retag_cause,
824
824
new_tag,
0 commit comments