1+ use std:: borrow:: Cow ;
2+ use std:: cell:: Cell ;
3+ use std:: fs:: File ;
4+ use std:: io:: { BufWriter , Write } ;
5+ use std:: path:: PathBuf ;
6+
17use cranelift_codegen:: Context ;
28use cranelift_codegen:: control:: ControlPlane ;
39use cranelift_codegen:: incremental_cache:: CacheKvStore ;
@@ -8,19 +14,30 @@ use cranelift_module::{
814 ModuleReloc , ModuleResult ,
915} ;
1016use cranelift_object:: { ObjectModule , ObjectProduct } ;
17+ use rustc_data_structures:: fx:: FxHashMap ;
18+ use rustc_data_structures:: owned_slice:: { OwnedSlice , slice_owned} ;
1119
1220use crate :: UnwindContext ;
1321
1422/// A wrapper around a [Module] which adds any defined function to the [UnwindContext].
1523pub ( crate ) struct UnwindModule < T > {
1624 pub ( crate ) module : T ,
1725 unwind_context : UnwindContext ,
26+ cache : Option < Box < dyn CacheKvStore + Send > > ,
1827}
1928
2029impl < T : Module > UnwindModule < T > {
21- pub ( crate ) fn new ( mut module : T , pic_eh_frame : bool ) -> Self {
30+ pub ( crate ) fn new ( mut module : T , cgu_name : & str , pic_eh_frame : bool ) -> Self {
2231 let unwind_context = UnwindContext :: new ( & mut module, pic_eh_frame) ;
23- UnwindModule { module, unwind_context }
32+ let cache = match std:: env:: var ( "CG_CLIF_FUNCTION_CACHE" ) . as_deref ( ) {
33+ Err ( _) => None ,
34+ Ok ( "naive" ) => Some ( Box :: new ( FileCache ) as Box < dyn CacheKvStore + Send > ) ,
35+ Ok ( "module" ) => {
36+ Some ( Box :: new ( ModuleCache :: new ( cgu_name) ) as Box < dyn CacheKvStore + Send > )
37+ }
38+ _ => panic ! ( ) ,
39+ } ;
40+ UnwindModule { module, unwind_context, cache }
2441 }
2542}
2643
@@ -91,13 +108,13 @@ impl<T: Module> Module for UnwindModule<T> {
91108 ctx : & mut Context ,
92109 ctrl_plane : & mut ControlPlane ,
93110 ) -> ModuleResult < ( ) > {
94- if std :: env :: var ( "CG_CLIF_FUNCTION_CACHE" ) . as_deref ( ) == Ok ( "naive" ) {
111+ if let Some ( cache ) = & mut self . cache {
95112 if ctx. func . layout . blocks ( ) . nth ( 1 ) . is_none ( )
96113 || ctx. func . layout . blocks ( ) . nth ( 2 ) . is_none ( )
97114 {
98115 ctx. compile ( self . module . isa ( ) , ctrl_plane) ?;
99116 } else {
100- ctx. compile_with_cache ( self . module . isa ( ) , & mut Cache , ctrl_plane) ?;
117+ ctx. compile_with_cache ( self . module . isa ( ) , & mut * * cache , ctrl_plane) ?;
101118 }
102119 } else {
103120 ctx. compile ( self . module . isa ( ) , ctrl_plane) ?;
@@ -132,18 +149,18 @@ impl<T: Module> Module for UnwindModule<T> {
132149 }
133150}
134151
135- struct Cache ;
152+ struct FileCache ;
136153
137- impl Cache {
154+ impl FileCache {
138155 fn file_for_key ( & self , key : & [ u8 ] ) -> String {
139156 let mut path = key. iter ( ) . map ( |b| format ! ( "{:02x}" , b) ) . collect :: < String > ( ) ;
140157 path. push_str ( ".clif_cache" ) ;
141158 "/home/bjorn/Projects/cg_clif/cache/" . to_owned ( ) + & path
142159 }
143160}
144161
145- impl CacheKvStore for Cache {
146- fn get ( & self , key : & [ u8 ] ) -> Option < std :: borrow :: Cow < ' _ , [ u8 ] > > {
162+ impl CacheKvStore for FileCache {
163+ fn get ( & self , key : & [ u8 ] ) -> Option < Cow < ' _ , [ u8 ] > > {
147164 let path = self . file_for_key ( key) ;
148165 if std:: fs:: exists ( & path) . unwrap ( ) {
149166 Some ( std:: fs:: read ( path) . unwrap ( ) . into ( ) )
@@ -157,3 +174,64 @@ impl CacheKvStore for Cache {
157174 std:: fs:: write ( path, val) . unwrap ( ) ;
158175 }
159176}
177+
178+ struct ModuleCache {
179+ file : PathBuf ,
180+ entries : FxHashMap < [ u8 ; 32 ] , ( OwnedSlice , Cell < bool > ) > ,
181+ }
182+
183+ impl ModuleCache {
184+ fn new ( name : & str ) -> Self {
185+ let file = PathBuf :: from ( "/home/bjorn/Projects/cg_clif/cache/" . to_owned ( ) + & name) ;
186+
187+ if !file. exists ( ) {
188+ return ModuleCache { file, entries : FxHashMap :: default ( ) } ;
189+ }
190+
191+ let data = std:: fs:: read ( & file) . unwrap ( ) ;
192+ let mut data = slice_owned ( data, |data| & data) ;
193+ let mut entries = FxHashMap :: default ( ) ;
194+ while !data. is_empty ( ) {
195+ let key: [ u8 ; 32 ] = data[ ..32 ] . try_into ( ) . unwrap ( ) ;
196+ let size = u32:: from_le_bytes ( data[ 32 ..36 ] . try_into ( ) . unwrap ( ) ) ;
197+ entries. insert (
198+ key,
199+ ( data. clone ( ) . slice ( |data| & data[ 20 ..size as usize + 36 ] ) , Cell :: new ( false ) ) ,
200+ ) ;
201+ data = data. slice ( |data| & data[ size as usize + 36 ..] ) ;
202+ }
203+
204+ ModuleCache { file, entries }
205+ }
206+ }
207+
208+ impl Drop for ModuleCache {
209+ fn drop ( & mut self ) {
210+ let mut buf_writer = BufWriter :: new ( File :: create ( & self . file ) . unwrap ( ) ) ;
211+ for ( key, ( data, accessed) ) in & self . entries {
212+ if !accessed. get ( ) {
213+ continue ;
214+ }
215+ buf_writer. write_all ( key) . unwrap ( ) ;
216+ buf_writer. write_all ( & u32:: to_le_bytes ( data. len ( ) as u32 ) ) . unwrap ( ) ;
217+ buf_writer. write_all ( data) . unwrap ( ) ;
218+ }
219+ buf_writer. into_inner ( ) . unwrap ( ) ;
220+ }
221+ }
222+
223+ impl CacheKvStore for ModuleCache {
224+ fn get ( & self , key : & [ u8 ] ) -> Option < Cow < ' _ , [ u8 ] > > {
225+ if let Some ( ( data, accessed) ) = self . entries . get :: < [ u8 ; 32 ] > ( key. try_into ( ) . unwrap ( ) ) {
226+ accessed. set ( true ) ;
227+ Some ( Cow :: Borrowed ( & * data) )
228+ } else {
229+ None
230+ }
231+ }
232+
233+ fn insert ( & mut self , key : & [ u8 ] , val : Vec < u8 > ) {
234+ self . entries
235+ . insert ( key. try_into ( ) . unwrap ( ) , ( slice_owned ( val, |val| & val) , Cell :: new ( true ) ) ) ;
236+ }
237+ }
0 commit comments