99// except according to those terms.
1010
1111use hir:: def_id:: DefId ;
12+ use rustc_data_structures:: fnv:: FnvHashMap ;
13+ use session:: config:: OutputType ;
14+ use std:: cell:: { Ref , RefCell } ;
1215use std:: rc:: Rc ;
16+ use std:: sync:: Arc ;
1317
14- use super :: dep_node:: DepNode ;
18+ use super :: dep_node:: { DepNode , WorkProductId } ;
1519use super :: query:: DepGraphQuery ;
1620use super :: raii;
1721use super :: thread:: { DepGraphThreadData , DepMessage } ;
1822
1923#[ derive( Clone ) ]
2024pub struct DepGraph {
21- data : Rc < DepGraphThreadData >
25+ data : Rc < DepGraphData >
26+ }
27+
28+ struct DepGraphData {
29+ /// We send messages to the thread to let it build up the dep-graph
30+ /// from the current run.
31+ thread : DepGraphThreadData ,
32+
33+ /// When we load, there may be `.o` files, cached mir, or other such
34+ /// things available to us. If we find that they are not dirty, we
35+ /// load the path to the file storing those work-products here into
36+ /// this map. We can later look for and extract that data.
37+ previous_work_products : RefCell < FnvHashMap < Arc < WorkProductId > , WorkProduct > > ,
38+
39+ /// Work-products that we generate in this run.
40+ work_products : RefCell < FnvHashMap < Arc < WorkProductId > , WorkProduct > > ,
2241}
2342
2443impl DepGraph {
2544 pub fn new ( enabled : bool ) -> DepGraph {
2645 DepGraph {
27- data : Rc :: new ( DepGraphThreadData :: new ( enabled) )
46+ data : Rc :: new ( DepGraphData {
47+ thread : DepGraphThreadData :: new ( enabled) ,
48+ previous_work_products : RefCell :: new ( FnvHashMap ( ) ) ,
49+ work_products : RefCell :: new ( FnvHashMap ( ) )
50+ } )
2851 }
2952 }
3053
3154 /// True if we are actually building a dep-graph. If this returns false,
3255 /// then the other methods on this `DepGraph` will have no net effect.
3356 #[ inline]
3457 pub fn enabled ( & self ) -> bool {
35- self . data . enabled ( )
58+ self . data . thread . enabled ( )
3659 }
3760
3861 pub fn query ( & self ) -> DepGraphQuery < DefId > {
39- self . data . query ( )
62+ self . data . thread . query ( )
4063 }
4164
4265 pub fn in_ignore < ' graph > ( & ' graph self ) -> raii:: IgnoreTask < ' graph > {
43- raii:: IgnoreTask :: new ( & self . data )
66+ raii:: IgnoreTask :: new ( & self . data . thread )
4467 }
4568
4669 pub fn in_task < ' graph > ( & ' graph self , key : DepNode < DefId > ) -> raii:: DepTask < ' graph > {
47- raii:: DepTask :: new ( & self . data , key)
70+ raii:: DepTask :: new ( & self . data . thread , key)
4871 }
4972
5073 pub fn with_ignore < OP , R > ( & self , op : OP ) -> R
@@ -62,10 +85,84 @@ impl DepGraph {
6285 }
6386
6487 pub fn read ( & self , v : DepNode < DefId > ) {
65- self . data . enqueue ( DepMessage :: Read ( v) ) ;
88+ self . data . thread . enqueue ( DepMessage :: Read ( v) ) ;
6689 }
6790
6891 pub fn write ( & self , v : DepNode < DefId > ) {
69- self . data . enqueue ( DepMessage :: Write ( v) ) ;
92+ self . data . thread . enqueue ( DepMessage :: Write ( v) ) ;
93+ }
94+
95+ /// Indicates that a previous work product exists for `v`. This is
96+ /// invoked during initial start-up based on what nodes are clean
97+ /// (and what files exist in the incr. directory).
98+ pub fn insert_previous_work_product ( & self , v : & Arc < WorkProductId > , data : WorkProduct ) {
99+ debug ! ( "insert_previous_work_product({:?}, {:?})" , v, data) ;
100+ self . data . previous_work_products . borrow_mut ( )
101+ . insert ( v. clone ( ) , data) ;
102+ }
103+
104+ /// Indicates that we created the given work-product in this run
105+ /// for `v`. This record will be preserved and loaded in the next
106+ /// run.
107+ pub fn insert_work_product ( & self , v : & Arc < WorkProductId > , data : WorkProduct ) {
108+ debug ! ( "insert_work_product({:?}, {:?})" , v, data) ;
109+ self . data . work_products . borrow_mut ( )
110+ . insert ( v. clone ( ) , data) ;
70111 }
112+
113+ /// Check whether a previous work product exists for `v` and, if
114+ /// so, return the path that leads to it. Used to skip doing work.
115+ pub fn previous_work_product ( & self , v : & Arc < WorkProductId > ) -> Option < WorkProduct > {
116+ self . data . previous_work_products . borrow ( )
117+ . get ( v)
118+ . cloned ( )
119+ }
120+
121+ /// Access the map of work-products created during this run. Only
122+ /// used during saving of the dep-graph.
123+ pub fn work_products ( & self ) -> Ref < FnvHashMap < Arc < WorkProductId > , WorkProduct > > {
124+ self . data . work_products . borrow ( )
125+ }
126+ }
127+
128+ /// A "work product" is an intermediate result that we save into the
129+ /// incremental directory for later re-use. The primary example are
130+ /// the object files that we save for each partition at code
131+ /// generation time.
132+ ///
133+ /// Each work product is associated with a dep-node, representing the
134+ /// process that produced the work-product. If that dep-node is found
135+ /// to be dirty when we load up, then we will delete the work-product
136+ /// at load time. If the work-product is found to be clean, then we
137+ /// will keep a record in the `previous_work_products` list.
138+ ///
139+ /// In addition, work products have an associated hash. This hash is
140+ /// an extra hash that can be used to decide if the work-product from
141+ /// a previous compilation can be re-used (in addition to the dirty
142+ /// edges check).
143+ ///
144+ /// As the primary example, consider the object files we generate for
145+ /// each partition. In the first run, we create partitions based on
146+ /// the symbols that need to be compiled. For each partition P, we
147+ /// hash the symbols in P and create a `WorkProduct` record associated
148+ /// with `DepNode::TransPartition(P)`; the hash is the set of symbols
149+ /// in P.
150+ ///
151+ /// The next time we compile, if the `DepNode::TransPartition(P)` is
152+ /// judged to be clean (which means none of the things we read to
153+ /// generate the partition were found to be dirty), it will be loaded
154+ /// into previous work products. We will then regenerate the set of
155+ /// symbols in the partition P and hash them (note that new symbols
156+ /// may be added -- for example, new monomorphizations -- even if
157+ /// nothing in P changed!). We will compare that hash against the
158+ /// previous hash. If it matches up, we can reuse the object file.
159+ #[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
160+ pub struct WorkProduct {
161+ /// Extra hash used to decide if work-product is still suitable;
162+ /// note that this is *not* a hash of the work-product itself.
163+ /// See documentation on `WorkProduct` type for an example.
164+ pub input_hash : u64 ,
165+
166+ /// Saved files associated with this CGU
167+ pub saved_files : Vec < ( OutputType , String ) > ,
71168}
0 commit comments