32
32
//! Because of that, we can assume that the only way to change the value behind a tracked place is
33
33
//! by direct assignment.
34
34
35
+ use std:: collections:: VecDeque ;
35
36
use std:: fmt:: { Debug , Formatter } ;
36
37
37
38
use rustc_data_structures:: fx:: FxHashMap ;
@@ -608,7 +609,7 @@ impl Map {
608
609
pub fn from_filter < ' tcx > (
609
610
tcx : TyCtxt < ' tcx > ,
610
611
body : & Body < ' tcx > ,
611
- filter : impl FnMut ( Ty < ' tcx > ) -> bool ,
612
+ filter : impl Fn ( Ty < ' tcx > ) -> bool ,
612
613
place_limit : Option < usize > ,
613
614
) -> Self {
614
615
let mut map = Self :: new ( ) ;
@@ -623,51 +624,67 @@ impl Map {
623
624
& mut self ,
624
625
tcx : TyCtxt < ' tcx > ,
625
626
body : & Body < ' tcx > ,
626
- mut filter : impl FnMut ( Ty < ' tcx > ) -> bool ,
627
+ filter : impl Fn ( Ty < ' tcx > ) -> bool ,
627
628
exclude : BitSet < Local > ,
628
629
place_limit : Option < usize > ,
629
630
) {
630
631
// We use this vector as stack, pushing and popping projections.
631
- let mut projection = Vec :: new ( ) ;
632
+ let mut worklist = VecDeque :: with_capacity ( place_limit. unwrap_or ( body. local_decls . len ( ) ) ) ;
633
+ self . locals = IndexVec :: from_elem ( None , & body. local_decls ) ;
632
634
for ( local, decl) in body. local_decls . iter_enumerated ( ) {
633
- if !exclude. contains ( local) {
634
- self . register_with_filter_rec (
635
- tcx,
636
- local,
637
- & mut projection,
638
- decl. ty ,
639
- & mut filter,
640
- place_limit,
641
- ) ;
635
+ if exclude. contains ( local) {
636
+ continue ;
642
637
}
638
+
639
+ // Create a place for the local.
640
+ debug_assert ! ( self . locals[ local] . is_none( ) ) ;
641
+ let place = self . places . push ( PlaceInfo :: new ( None ) ) ;
642
+ self . locals [ local] = Some ( place) ;
643
+
644
+ // And push the eventual children places to the worklist.
645
+ self . register_children ( tcx, place, decl. ty , & filter, & mut worklist) ;
646
+ }
647
+
648
+ // `place.elem1.elem2` with type `ty`.
649
+ while let Some ( ( mut place, elem1, elem2, ty) ) = worklist. pop_front ( ) {
650
+ if let Some ( place_limit) = place_limit && self . value_count >= place_limit {
651
+ break
652
+ }
653
+
654
+ // Create a place for this projection.
655
+ for elem in [ elem1, Some ( elem2) ] . into_iter ( ) . flatten ( ) {
656
+ place = * self . projections . entry ( ( place, elem) ) . or_insert_with ( || {
657
+ // Prepend new child to the linked list.
658
+ let next = self . places . push ( PlaceInfo :: new ( Some ( elem) ) ) ;
659
+ self . places [ next] . next_sibling = self . places [ place] . first_child ;
660
+ self . places [ place] . first_child = Some ( next) ;
661
+ next
662
+ } ) ;
663
+ }
664
+
665
+ // And push the eventual children places to the worklist.
666
+ self . register_children ( tcx, place, ty, & filter, & mut worklist) ;
643
667
}
644
668
}
645
669
646
670
/// Potentially register the (local, projection) place and its fields, recursively.
647
671
///
648
672
/// Invariant: The projection must only contain trackable elements.
649
- fn register_with_filter_rec < ' tcx > (
673
+ fn register_children < ' tcx > (
650
674
& mut self ,
651
675
tcx : TyCtxt < ' tcx > ,
652
- local : Local ,
653
- projection : & mut Vec < PlaceElem < ' tcx > > ,
676
+ place : PlaceIndex ,
654
677
ty : Ty < ' tcx > ,
655
- filter : & mut impl FnMut ( Ty < ' tcx > ) -> bool ,
656
- place_limit : Option < usize > ,
678
+ filter : & impl Fn ( Ty < ' tcx > ) -> bool ,
679
+ worklist : & mut VecDeque < ( PlaceIndex , Option < TrackElem > , TrackElem , Ty < ' tcx > ) > ,
657
680
) {
658
- if let Some ( place_limit) = place_limit && self . value_count >= place_limit {
659
- return
660
- }
661
-
662
- // We know that the projection only contains trackable elements.
663
- let place = self . make_place ( local, projection) . unwrap ( ) ;
664
-
665
681
// Allocate a value slot if it doesn't have one, and the user requested one.
666
682
if self . places [ place] . value_index . is_none ( ) && filter ( ty) {
667
683
self . places [ place] . value_index = Some ( self . value_count . into ( ) ) ;
668
684
self . value_count += 1 ;
669
685
}
670
686
687
+ // For enums, directly create the `Discriminant`, as that's their main use.
671
688
if ty. is_enum ( ) {
672
689
let discr_ty = ty. discriminant_ty ( tcx) ;
673
690
if filter ( discr_ty) {
@@ -692,48 +709,15 @@ impl Map {
692
709
693
710
// Recurse with all fields of this place.
694
711
iter_fields ( ty, tcx, ty:: ParamEnv :: reveal_all ( ) , |variant, field, ty| {
695
- if let Some ( variant) = variant {
696
- projection. push ( PlaceElem :: Downcast ( None , variant) ) ;
697
- let _ = self . make_place ( local, projection) ;
698
- projection. push ( PlaceElem :: Field ( field, ty) ) ;
699
- self . register_with_filter_rec ( tcx, local, projection, ty, filter, place_limit) ;
700
- projection. pop ( ) ;
701
- projection. pop ( ) ;
702
- return ;
703
- }
704
- projection. push ( PlaceElem :: Field ( field, ty) ) ;
705
- self . register_with_filter_rec ( tcx, local, projection, ty, filter, place_limit) ;
706
- projection. pop ( ) ;
712
+ worklist. push_back ( (
713
+ place,
714
+ variant. map ( TrackElem :: Variant ) ,
715
+ TrackElem :: Field ( field) ,
716
+ ty,
717
+ ) )
707
718
} ) ;
708
719
}
709
720
710
- /// Tries to add the place to the map, without allocating a value slot.
711
- ///
712
- /// Can fail if the projection contains non-trackable elements.
713
- fn make_place < ' tcx > (
714
- & mut self ,
715
- local : Local ,
716
- projection : & [ PlaceElem < ' tcx > ] ,
717
- ) -> Result < PlaceIndex , ( ) > {
718
- // Get the base index of the local.
719
- let mut index =
720
- * self . locals . get_or_insert_with ( local, || self . places . push ( PlaceInfo :: new ( None ) ) ) ;
721
-
722
- // Apply the projection.
723
- for & elem in projection {
724
- let elem = elem. try_into ( ) ?;
725
- index = * self . projections . entry ( ( index, elem) ) . or_insert_with ( || {
726
- // Prepend new child to the linked list.
727
- let next = self . places . push ( PlaceInfo :: new ( Some ( elem) ) ) ;
728
- self . places [ next] . next_sibling = self . places [ index] . first_child ;
729
- self . places [ index] . first_child = Some ( next) ;
730
- next
731
- } ) ;
732
- }
733
-
734
- Ok ( index)
735
- }
736
-
737
721
/// Returns the number of tracked places, i.e., those for which a value can be stored.
738
722
pub fn tracked_places ( & self ) -> usize {
739
723
self . value_count
@@ -750,7 +734,7 @@ impl Map {
750
734
place : PlaceRef < ' _ > ,
751
735
extra : impl IntoIterator < Item = TrackElem > ,
752
736
) -> Option < PlaceIndex > {
753
- let mut index = * self . locals . get ( place. local ) ? . as_ref ( ) ?;
737
+ let mut index = * self . locals [ place. local ] . as_ref ( ) ?;
754
738
755
739
for & elem in place. projection {
756
740
index = self . apply ( index, elem. try_into ( ) . ok ( ) ?) ?;
@@ -794,7 +778,7 @@ impl Map {
794
778
// We do not track indirect places.
795
779
return ;
796
780
}
797
- let Some ( & Some ( mut index) ) = self . locals . get ( place. local ) else {
781
+ let Some ( mut index) = self . locals [ place. local ] else {
798
782
// The local is not tracked at all, so it does not alias anything.
799
783
return ;
800
784
} ;
0 commit comments