@@ -51,7 +51,7 @@ use rustc_data_structures::outline;
5151use rustc_data_structures:: profiling:: SelfProfilerRef ;
5252use rustc_data_structures:: sync:: { AtomicU64 , Lock , WorkerLocal , broadcast} ;
5353use rustc_data_structures:: unhash:: UnhashMap ;
54- use rustc_index:: IndexVec ;
54+ use rustc_index:: { IndexSlice , IndexVec } ;
5555use rustc_serialize:: opaque:: mem_encoder:: MemEncoder ;
5656use rustc_serialize:: opaque:: { FileEncodeResult , FileEncoder , IntEncodedWithFixedSize , MemDecoder } ;
5757use rustc_serialize:: { Decodable , Decoder , Encodable , Encoder } ;
@@ -116,7 +116,7 @@ pub struct SerializedDepGraph {
116116 /// The lazily-built inverse of `nodes`: maps a [`DepNode`] back to its
117117 /// [`SerializedDepNodeIndex`] via the node's key fingerprint. See
118118 /// [`LazyNodeIndex`].
119- index : LazyNodeIndex ,
119+ reverse_index : LazyNodeIndex ,
120120 /// The number of previous compilation sessions. This is used to generate
121121 /// unique anon dep nodes per session.
122122 session_count : u64 ,
@@ -140,8 +140,11 @@ pub struct SerializedDepGraph {
140140#[ derive( Debug , Default ) ]
141141struct LazyNodeIndex {
142142 /// All (non-`Null`) node indices, grouped into contiguous per-`DepKind`
143- /// ranges described by `kinds`.
144- nodes_by_kind : Vec < SerializedDepNodeIndex > ,
143+ /// ranges described by `kinds`. Allocated with `None` in every slot; the
144+ /// counting sort in `decode` fills each slot of every range exactly once, so a
145+ /// `None` is never read back. `SerializedDepNodeIndex` has a niche, so the
146+ /// `Option` does not grow the vector.
147+ nodes_by_kind : Vec < Option < SerializedDepNodeIndex > > ,
145148 /// For each `DepKind`, the range of `nodes_by_kind` holding its node indices
146149 /// and the lazily-built fingerprint map over that range.
147150 kinds : Vec < LazyKindIndex > ,
@@ -158,6 +161,43 @@ struct LazyKindIndex {
158161 map : OnceLock < UnhashMap < PackedFingerprint , SerializedDepNodeIndex > > ,
159162}
160163
164+ impl LazyKindIndex {
165+ /// Returns this kind's `key_fingerprint -> node index` map, building it from
166+ /// the kind's range of `nodes_by_kind` on the first call. Building does the
167+ /// per-node hash-map inserts that decode used to perform eagerly for every
168+ /// kind; here we only pay it for kinds that are actually looked up.
169+ fn fingerprint_map (
170+ & self ,
171+ kind : DepKind ,
172+ nodes : & IndexSlice < SerializedDepNodeIndex , DepNode > ,
173+ nodes_by_kind : & [ Option < SerializedDepNodeIndex > ] ,
174+ ) -> & UnhashMap < PackedFingerprint , SerializedDepNodeIndex > {
175+ self . map . get_or_init ( || {
176+ let range = ( self . start as usize ) ..( self . start as usize + self . len as usize ) ;
177+ let mut map =
178+ UnhashMap :: with_capacity_and_hasher ( self . len as usize , Default :: default ( ) ) ;
179+ for & idx in & nodes_by_kind[ range] {
180+ let idx = idx. expect ( "counting sort fills every slot of a kind's range" ) ;
181+ let node = & nodes[ idx] ;
182+ debug_assert_eq ! ( node. kind, kind) ;
183+ if map. insert ( node. key_fingerprint , idx) . is_some ( )
184+ // Side effect nodes can legitimately share a fingerprint.
185+ && node. kind != DepKind :: SideEffect
186+ {
187+ panic ! (
188+ "Error: A dep graph node ({kind:?}) does not have an unique index. \
189+ Running a clean build on a nightly compiler with \
190+ `-Z incremental-verify-ich` can help narrow down the issue for reporting. \
191+ A clean build may also work around the issue.\n
192+ DepNode: {node:?}"
193+ )
194+ }
195+ }
196+ map
197+ } )
198+ }
199+ }
200+
161201impl SerializedDepGraph {
162202 #[ inline]
163203 pub fn edge_targets_from (
@@ -188,28 +228,9 @@ impl SerializedDepGraph {
188228
189229 #[ inline]
190230 pub fn node_to_index_opt ( & self , dep_node : & DepNode ) -> Option < SerializedDepNodeIndex > {
191- let kind = self . index . kinds . get ( dep_node. kind . as_usize ( ) ) ?;
192- let map = kind. map . get_or_init ( || {
193- let range = ( kind. start as usize ) ..( kind. start as usize + kind. len as usize ) ;
194- let mut map = UnhashMap :: with_capacity_and_hasher ( kind. len as usize , Default :: default ( ) ) ;
195- for & idx in & self . index . nodes_by_kind [ range] {
196- let node = & self . nodes [ idx] ;
197- if map. insert ( node. key_fingerprint , idx) . is_some ( )
198- // Side effect nodes can legitimately share a fingerprint.
199- && node. kind != DepKind :: SideEffect
200- {
201- panic ! (
202- "Error: A dep graph node ({:?}) does not have an unique index. \
203- Running a clean build on a nightly compiler with \
204- `-Z incremental-verify-ich` can help narrow down the issue for reporting. \
205- A clean build may also work around the issue.\n
206- DepNode: {node:?}" ,
207- node. kind
208- )
209- }
210- }
211- map
212- } ) ;
231+ let kind = self . reverse_index . kinds . get ( dep_node. kind . as_usize ( ) ) ?;
232+ let map =
233+ kind. fingerprint_map ( dep_node. kind , & self . nodes , & self . reverse_index . nodes_by_kind ) ;
213234 map. get ( & dep_node. key_fingerprint ) . copied ( )
214235 }
215236
@@ -345,43 +366,49 @@ impl SerializedDepGraph {
345366 // end of the array. This padding ensure it doesn't.
346367 edge_list_data. extend ( & [ 0u8 ; DEP_NODE_PAD ] ) ;
347368
348- // Read the number of nodes of each dep kind. These per-kind counts let us
349- // group node indices by kind below; the fingerprint -> index maps
350- // themselves are built lazily, per kind, on first lookup (see
351- // `LazyNodeIndex`).
352- let kind_counts: Vec < u32 > = ( 0 ..( DepKind :: MAX + 1 ) ) . map ( |_| d. read_u32 ( ) ) . collect ( ) ;
353-
354- let session_count = d. read_u64 ( ) ;
355-
356- // Counting sort: place every (non-`Null`) node index into a contiguous
357- // per-kind range of `nodes_by_kind`, using the per-kind counts to compute
358- // each kind's start offset. Padding gaps (`DepKind::Null`) are never
359- // looked up by fingerprint, so we skip them.
360- let mut kinds = Vec :: with_capacity ( kind_counts. len ( ) ) ;
369+ // Read the number of nodes of each dep kind, turning each per-kind count
370+ // into a contiguous, still-empty range of `nodes_by_kind` as we go (a
371+ // prefix sum of the counts gives each kind's start offset). The
372+ // fingerprint -> index map for a kind is built lazily, on the first lookup
373+ // of that kind (see `LazyKindIndex::fingerprint_map`).
374+ let mut kinds = Vec :: with_capacity ( DepKind :: MAX as usize + 1 ) ;
361375 let mut offset = 0u32 ;
362- for & len in & kind_counts {
376+ for _ in 0 ..( DepKind :: MAX + 1 ) {
377+ let len = d. read_u32 ( ) ;
363378 kinds. push ( LazyKindIndex { start : offset, len, map : OnceLock :: new ( ) } ) ;
364379 offset += len;
365380 }
381+ // Every encoded node has a (non-`Null`) kind, so the per-kind counts sum to
382+ // `node_count`; `Null` nodes are never encoded, so no range is reserved for
383+ // them.
366384 debug_assert_eq ! ( offset as usize , node_count) ;
367- let mut nodes_by_kind = vec ! [ SerializedDepNodeIndex :: from_u32( 0 ) ; offset as usize ] ;
385+
386+ let session_count = d. read_u64 ( ) ;
387+
388+ // Counting sort: place each node index into its kind's range. `fill[k]`
389+ // points at the next free slot in kind `k`'s range, so a kind's nodes end
390+ // up contiguous. Slots start as `None` and are each filled exactly once
391+ // (the counts sum to the number of non-`Null` nodes).
392+ let mut nodes_by_kind = vec ! [ None ; node_count] ;
368393 let mut fill: Vec < u32 > = kinds. iter ( ) . map ( |k| k. start ) . collect ( ) ;
369394 for ( idx, node) in nodes. iter_enumerated ( ) {
395+ // Unused indices from batch allocation stay `Null`; they carry no
396+ // encoded node and are never looked up by fingerprint, so skip them.
370397 if node. kind == DepKind :: Null {
371398 continue ;
372399 }
373400 let k = node. kind . as_usize ( ) ;
374- nodes_by_kind[ fill[ k] as usize ] = idx;
401+ nodes_by_kind[ fill[ k] as usize ] = Some ( idx) ;
375402 fill[ k] += 1 ;
376403 }
377- let index = LazyNodeIndex { nodes_by_kind, kinds } ;
404+ let reverse_index = LazyNodeIndex { nodes_by_kind, kinds } ;
378405
379406 Arc :: new ( SerializedDepGraph {
380407 nodes,
381408 value_fingerprints,
382409 edge_list_indices,
383410 edge_list_data,
384- index ,
411+ reverse_index ,
385412 session_count,
386413 } )
387414 }
0 commit comments