188188//! this is not implemented however: a translation item will be produced
189189//! regardless of whether it is actually needed or not.
190190
191+ use rustc_data_structures:: bitvec:: BitVector ;
192+
191193use rustc:: hir;
192194use rustc:: hir:: intravisit as hir_visit;
193195
@@ -252,12 +254,76 @@ impl<'tcx> Hash for TransItem<'tcx> {
252254 }
253255}
254256
255- pub type InliningMap < ' tcx > = FnvHashMap < TransItem < ' tcx > , FnvHashSet < TransItem < ' tcx > > > ;
257+ /// Maps every translation item to all translation items it references in its
258+ /// body.
259+ pub struct ReferenceMap < ' tcx > {
260+ // Maps a source translation item to a range of target translation items.
261+ // The two numbers in the tuple are the start (inclusive) and
262+ // end index (exclusive) within the `targets` and the `inlined` vecs.
263+ index : FnvHashMap < TransItem < ' tcx > , ( usize , usize ) > ,
264+ targets : Vec < TransItem < ' tcx > > ,
265+ inlined : BitVector
266+ }
267+
268+ impl < ' tcx > ReferenceMap < ' tcx > {
269+
270+ fn new ( ) -> ReferenceMap < ' tcx > {
271+ ReferenceMap {
272+ index : FnvHashMap ( ) ,
273+ targets : Vec :: new ( ) ,
274+ inlined : BitVector :: new ( 64 * 256 ) ,
275+ }
276+ }
277+
278+ fn record_references < I > ( & mut self , source : TransItem < ' tcx > , targets : I )
279+ where I : Iterator < Item =( TransItem < ' tcx > , bool ) >
280+ {
281+ assert ! ( !self . index. contains_key( & source) ) ;
282+
283+ let start_index = self . targets . len ( ) ;
284+
285+ for ( target, inlined) in targets {
286+ let index = self . targets . len ( ) ;
287+ self . targets . push ( target) ;
288+ self . inlined . grow ( index + 1 ) ;
289+
290+ if inlined {
291+ self . inlined . insert ( index) ;
292+ }
293+ }
294+
295+ let end_index = self . targets . len ( ) ;
296+ self . index . insert ( source, ( start_index, end_index) ) ;
297+ }
298+
299+ // Internally iterate over all items referenced by `source` which will be
300+ // made available for inlining.
301+ pub fn with_inlining_candidates < F > ( & self , source : TransItem < ' tcx > , mut f : F )
302+ where F : FnMut ( TransItem < ' tcx > ) {
303+ if let Some ( & ( start_index, end_index) ) = self . index . get ( & source)
304+ {
305+ for index in start_index .. end_index {
306+ if self . inlined . contains ( index) {
307+ f ( self . targets [ index] )
308+ }
309+ }
310+ }
311+ }
312+
313+ pub fn get_direct_references_from ( & self , source : TransItem < ' tcx > ) -> & [ TransItem < ' tcx > ]
314+ {
315+ if let Some ( & ( start_index, end_index) ) = self . index . get ( & source) {
316+ & self . targets [ start_index .. end_index]
317+ } else {
318+ & self . targets [ 0 .. 0 ]
319+ }
320+ }
321+ }
256322
257323pub fn collect_crate_translation_items < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > ,
258324 mode : TransItemCollectionMode )
259325 -> ( FnvHashSet < TransItem < ' tcx > > ,
260- InliningMap < ' tcx > ) {
326+ ReferenceMap < ' tcx > ) {
261327 // We are not tracking dependencies of this pass as it has to be re-executed
262328 // every time no matter what.
263329 ccx. tcx ( ) . dep_graph . with_ignore ( || {
@@ -266,17 +332,17 @@ pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
266332 debug ! ( "Building translation item graph, beginning at roots" ) ;
267333 let mut visited = FnvHashSet ( ) ;
268334 let mut recursion_depths = DefIdMap ( ) ;
269- let mut inlining_map = FnvHashMap ( ) ;
335+ let mut reference_map = ReferenceMap :: new ( ) ;
270336
271337 for root in roots {
272338 collect_items_rec ( ccx,
273339 root,
274340 & mut visited,
275341 & mut recursion_depths,
276- & mut inlining_map ) ;
342+ & mut reference_map ) ;
277343 }
278344
279- ( visited, inlining_map )
345+ ( visited, reference_map )
280346 } )
281347}
282348
@@ -307,7 +373,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
307373 starting_point : TransItem < ' tcx > ,
308374 visited : & mut FnvHashSet < TransItem < ' tcx > > ,
309375 recursion_depths : & mut DefIdMap < usize > ,
310- inlining_map : & mut InliningMap < ' tcx > ) {
376+ reference_map : & mut ReferenceMap < ' tcx > ) {
311377 if !visited. insert ( starting_point. clone ( ) ) {
312378 // We've been here already, no need to search again.
313379 return ;
@@ -351,9 +417,10 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
351417 }
352418 }
353419
420+ record_references ( ccx, starting_point, & neighbors[ ..] , reference_map) ;
421+
354422 for neighbour in neighbors {
355- record_inlined_use ( ccx, starting_point, neighbour, inlining_map) ;
356- collect_items_rec ( ccx, neighbour, visited, recursion_depths, inlining_map) ;
423+ collect_items_rec ( ccx, neighbour, visited, recursion_depths, reference_map) ;
357424 }
358425
359426 if let Some ( ( def_id, depth) ) = recursion_depth_reset {
@@ -363,16 +430,17 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
363430 debug ! ( "END collect_items_rec({})" , starting_point. to_string( ccx) ) ;
364431}
365432
366- fn record_inlined_use < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > ,
367- caller : TransItem < ' tcx > ,
368- callee : TransItem < ' tcx > ,
369- inlining_map : & mut InliningMap < ' tcx > ) {
370- if callee. is_from_extern_crate ( ) ||
371- callee. requests_inline ( ccx. tcx ( ) ) {
372- inlining_map. entry ( caller)
373- . or_insert_with ( || FnvHashSet ( ) )
374- . insert ( callee) ;
375- }
433+ fn record_references < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > ,
434+ caller : TransItem < ' tcx > ,
435+ callees : & [ TransItem < ' tcx > ] ,
436+ reference_map : & mut ReferenceMap < ' tcx > ) {
437+ let iter = callees. into_iter ( )
438+ . map ( |callee| {
439+ let is_inlining_candidate = callee. is_from_extern_crate ( ) ||
440+ callee. requests_inline ( ccx. tcx ( ) ) ;
441+ ( * callee, is_inlining_candidate)
442+ } ) ;
443+ reference_map. record_references ( caller, iter) ;
376444}
377445
378446fn check_recursion_limit < ' a , ' tcx : ' a > ( ccx : & CrateContext < ' a , ' tcx > ,
0 commit comments