@@ -5,17 +5,15 @@ use cranelift_codegen::ir;
5
5
use cranelift_codegen:: isa;
6
6
use directories:: ProjectDirs ;
7
7
use lazy_static:: lazy_static;
8
- use log:: warn;
8
+ use log:: { debug , warn} ;
9
9
use serde:: de:: { self , Deserialize , Deserializer , MapAccess , SeqAccess , Visitor } ;
10
10
use serde:: ser:: { self , Serialize , SerializeSeq , SerializeStruct , Serializer } ;
11
- #[ cfg( windows) ]
12
11
use std:: ffi:: OsString ;
13
12
use std:: fmt;
14
13
use std:: fs;
15
14
use std:: io;
16
- #[ cfg( windows) ]
17
- use std:: path:: Path ;
18
15
use std:: path:: PathBuf ;
16
+ use std:: string:: { String , ToString } ;
19
17
20
18
/// Module for configuring the cache system.
21
19
pub mod conf {
@@ -48,29 +46,47 @@ lazy_static! {
48
46
Some ( proj_dirs) => {
49
47
let cache_dir = proj_dirs. cache_dir( ) ;
50
48
// Temporary workaround for: https://github.com/rust-lang/rust/issues/32689
51
- #[ cfg( windows) ]
52
- let mut long_path = OsString :: from( "\\ \\ ?\\ " ) ;
53
- #[ cfg( windows) ]
54
- let cache_dir = {
55
- if cache_dir. starts_with( "\\ \\ ?\\ " ) {
56
- cache_dir
49
+ if cfg!( windows) {
50
+ let mut long_path = OsString :: new( ) ;
51
+ if !cache_dir. starts_with( "\\ \\ ?\\ " ) {
52
+ long_path. push( "\\ \\ ?\\ " ) ;
57
53
}
58
- else {
59
- long_path. push( cache_dir. as_os_str( ) ) ;
60
- Path :: new( & long_path)
61
- }
62
- } ;
63
- match fs:: create_dir_all( cache_dir) {
64
- Ok ( ( ) ) => ( ) ,
65
- Err ( err) => warn!( "Unable to create cache directory, failed with: {}" , err) ,
66
- } ;
67
- Some ( cache_dir. to_path_buf( ) )
54
+ long_path. push( cache_dir. as_os_str( ) ) ;
55
+ Some ( PathBuf :: from( long_path) )
56
+ }
57
+ else {
58
+ Some ( cache_dir. to_path_buf( ) )
59
+ }
68
60
}
69
61
None => {
70
- warn!( "Unable to find cache directory" ) ;
62
+ warn!( "Failed to find proper cache directory location. " ) ;
71
63
None
72
64
}
73
65
} ;
66
+ static ref SELF_MTIME : String = {
67
+ match std:: env:: current_exe( ) {
68
+ Ok ( path) => match fs:: metadata( & path) {
69
+ Ok ( metadata) => match metadata. modified( ) {
70
+ Ok ( mtime) => match mtime. duration_since( std:: time:: UNIX_EPOCH ) {
71
+ Ok ( duration) => format!( "{}" , duration. as_millis( ) ) ,
72
+ Err ( err) => format!( "m{}" , err. duration( ) . as_millis( ) ) ,
73
+ } ,
74
+ Err ( _) => {
75
+ warn!( "Failed to get modification time of current executable" ) ;
76
+ "no-mtime" . to_string( )
77
+ }
78
+ } ,
79
+ Err ( _) => {
80
+ warn!( "Failed to get metadata of current executable" ) ;
81
+ "no-mtime" . to_string( )
82
+ }
83
+ } ,
84
+ Err ( _) => {
85
+ warn!( "Failed to get path of current executable" ) ;
86
+ "no-mtime" . to_string( )
87
+ }
88
+ }
89
+ } ;
74
90
}
75
91
76
92
pub struct ModuleCacheEntry {
@@ -87,14 +103,33 @@ pub struct ModuleCacheData {
87
103
type ModuleCacheDataTupleType = ( Compilation , Relocations , ModuleAddressMap ) ;
88
104
89
105
impl ModuleCacheEntry {
90
- pub fn new ( module : & Module , _isa : & dyn isa:: TargetIsa , _generate_debug_info : bool ) -> Self {
91
- // TODO: cache directory hierarchy with isa name, compiler name & git revision, and files with flag if debug symbols are available
106
+ pub fn new (
107
+ module : & Module ,
108
+ isa : & dyn isa:: TargetIsa ,
109
+ compiler_name : & str ,
110
+ generate_debug_info : bool ,
111
+ ) -> Self {
92
112
let mod_cache_path = if conf:: cache_enabled ( ) {
93
113
CACHE_DIR . clone ( ) . and_then ( |p| {
94
114
module. hash . map ( |hash| {
95
- p. join ( format ! (
96
- "mod-{}" ,
97
- base64:: encode_config( & hash, base64:: URL_SAFE_NO_PAD ) // standard encoding uses '/' which can't be used for filename
115
+ let compiler_dir = if cfg ! ( debug_assertions) {
116
+ format ! (
117
+ "{comp_name}-{comp_ver}-{comp_mtime}" ,
118
+ comp_name = compiler_name,
119
+ comp_ver = env!( "GIT_REV" ) ,
120
+ comp_mtime = * SELF_MTIME ,
121
+ )
122
+ } else {
123
+ format ! (
124
+ "{comp_name}-{comp_ver}" ,
125
+ comp_name = compiler_name,
126
+ comp_ver = env!( "GIT_REV" ) ,
127
+ )
128
+ } ;
129
+ p. join ( isa. name ( ) ) . join ( compiler_dir) . join ( format ! (
130
+ "mod-{mod_hash}{mod_dbg}" ,
131
+ mod_hash = base64:: encode_config( & hash, base64:: URL_SAFE_NO_PAD ) , // standard encoding uses '/' which can't be used for filename
132
+ mod_dbg = if generate_debug_info { ".d" } else { "" } ,
98
133
) )
99
134
} )
100
135
} )
@@ -131,25 +166,46 @@ impl ModuleCacheEntry {
131
166
return ;
132
167
}
133
168
} ;
169
+ // Optimize syscalls: first, try writing to disk. It should succeed in most cases.
170
+ // Otherwise, try creating the cache directory and retry writing to the file.
134
171
match fs:: write ( p, & cache_buf) {
135
172
Ok ( ( ) ) => ( ) ,
136
173
Err ( err) => {
137
- warn ! (
138
- "Failed to write cached code to disk, path: {}, message: {}" ,
174
+ debug ! (
175
+ "Attempting to create the cache directory, because \
176
+ failed to write cached code to disk, path: {}, message: {}",
139
177
p. display( ) ,
140
- err
178
+ err,
141
179
) ;
142
- match fs:: remove_file ( p) {
143
- Ok ( ( ) ) => ( ) ,
144
- Err ( err) => {
145
- if err. kind ( ) != io:: ErrorKind :: NotFound {
180
+ let cache_dir = p. parent ( ) . unwrap ( ) ;
181
+ match fs:: create_dir_all ( cache_dir) {
182
+ Ok ( ( ) ) => match fs:: write ( p, & cache_buf) {
183
+ Ok ( ( ) ) => ( ) ,
184
+ Err ( err) => {
146
185
warn ! (
147
- "Failed to cleanup invalid cache , path: {}, message: {}" ,
186
+ "Failed to write cached code to disk , path: {}, message: {}" ,
148
187
p. display( ) ,
149
188
err
150
189
) ;
190
+ match fs:: remove_file ( p) {
191
+ Ok ( ( ) ) => ( ) ,
192
+ Err ( err) => {
193
+ if err. kind ( ) != io:: ErrorKind :: NotFound {
194
+ warn ! (
195
+ "Failed to cleanup invalid cache, path: {}, message: {}" ,
196
+ p. display( ) ,
197
+ err
198
+ ) ;
199
+ }
200
+ }
201
+ }
151
202
}
152
- }
203
+ } ,
204
+ Err ( err) => warn ! (
205
+ "Failed to create cache directory, path: {}, message: {}" ,
206
+ cache_dir. display( ) ,
207
+ err
208
+ ) ,
153
209
}
154
210
}
155
211
}
0 commit comments