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
+
1
7
use cranelift_codegen:: Context ;
2
8
use cranelift_codegen:: control:: ControlPlane ;
3
9
use cranelift_codegen:: incremental_cache:: CacheKvStore ;
@@ -8,19 +14,30 @@ use cranelift_module::{
8
14
ModuleReloc , ModuleResult ,
9
15
} ;
10
16
use cranelift_object:: { ObjectModule , ObjectProduct } ;
17
+ use rustc_data_structures:: fx:: FxHashMap ;
18
+ use rustc_data_structures:: owned_slice:: { OwnedSlice , slice_owned} ;
11
19
12
20
use crate :: UnwindContext ;
13
21
14
22
/// A wrapper around a [Module] which adds any defined function to the [UnwindContext].
15
23
pub ( crate ) struct UnwindModule < T > {
16
24
pub ( crate ) module : T ,
17
25
unwind_context : UnwindContext ,
26
+ cache : Option < Box < dyn CacheKvStore + Send > > ,
18
27
}
19
28
20
29
impl < 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 {
22
31
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 }
24
41
}
25
42
}
26
43
@@ -91,13 +108,13 @@ impl<T: Module> Module for UnwindModule<T> {
91
108
ctx : & mut Context ,
92
109
ctrl_plane : & mut ControlPlane ,
93
110
) -> ModuleResult < ( ) > {
94
- if std :: env :: var ( "CG_CLIF_FUNCTION_CACHE" ) . as_deref ( ) == Ok ( "naive" ) {
111
+ if let Some ( cache ) = & mut self . cache {
95
112
if ctx. func . layout . blocks ( ) . nth ( 1 ) . is_none ( )
96
113
|| ctx. func . layout . blocks ( ) . nth ( 2 ) . is_none ( )
97
114
{
98
115
ctx. compile ( self . module . isa ( ) , ctrl_plane) ?;
99
116
} 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) ?;
101
118
}
102
119
} else {
103
120
ctx. compile ( self . module . isa ( ) , ctrl_plane) ?;
@@ -132,18 +149,18 @@ impl<T: Module> Module for UnwindModule<T> {
132
149
}
133
150
}
134
151
135
- struct Cache ;
152
+ struct FileCache ;
136
153
137
- impl Cache {
154
+ impl FileCache {
138
155
fn file_for_key ( & self , key : & [ u8 ] ) -> String {
139
156
let mut path = key. iter ( ) . map ( |b| format ! ( "{:02x}" , b) ) . collect :: < String > ( ) ;
140
157
path. push_str ( ".clif_cache" ) ;
141
158
"/home/bjorn/Projects/cg_clif/cache/" . to_owned ( ) + & path
142
159
}
143
160
}
144
161
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 ] > > {
147
164
let path = self . file_for_key ( key) ;
148
165
if std:: fs:: exists ( & path) . unwrap ( ) {
149
166
Some ( std:: fs:: read ( path) . unwrap ( ) . into ( ) )
@@ -157,3 +174,64 @@ impl CacheKvStore for Cache {
157
174
std:: fs:: write ( path, val) . unwrap ( ) ;
158
175
}
159
176
}
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