@@ -12,6 +12,7 @@ pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage};
12
12
13
13
pub use self :: value:: { PrimVal , PrimValKind , Value , Pointer , ConstValue } ;
14
14
15
+ use std:: collections:: hash_map:: Entry ;
15
16
use std:: fmt;
16
17
use mir;
17
18
use hir:: def_id:: DefId ;
@@ -26,7 +27,7 @@ use std::hash::Hash;
26
27
use syntax:: ast:: Mutability ;
27
28
use rustc_serialize:: { Decodable , Encodable } ;
28
29
use rustc_data_structures:: sorted_map:: SortedMap ;
29
- use rustc_data_structures:: fx:: FxHashMap ;
30
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
30
31
use rustc_data_structures:: sync:: { HashMapExt , LockGuard } ;
31
32
use byteorder:: { WriteBytesExt , ReadBytesExt , LittleEndian , BigEndian } ;
32
33
@@ -191,10 +192,10 @@ where
191
192
return encoder. emit_usize ( alloc_pos) ;
192
193
}
193
194
let pos = encoder. position ( ) ;
195
+ assert ! ( cache( encoder) . insert( alloc_id, pos) . is_none( ) ) ;
194
196
trace ! ( "encoding {:?} with {:#?}" , alloc_id, alloc) ;
195
197
AllocKind :: Alloc . encode ( encoder) ?;
196
198
alloc. encode ( encoder) ?;
197
- cache ( encoder) . insert_same ( alloc_id, pos) ;
198
199
}
199
200
AllocType :: Function ( fn_instance) => {
200
201
trace ! ( "encoding {:?} with {:#?}" , alloc_id, fn_instance) ;
@@ -214,32 +215,65 @@ where
214
215
pub fn specialized_decode_alloc_id <
215
216
' a , ' tcx ,
216
217
D : TyDecoder < ' a , ' tcx > ,
217
- CACHE : FnOnce ( & mut D ) -> LockGuard < ' _ , FxHashMap < usize , AllocId > > ,
218
+ GlobalCache : FnMut ( & mut D ) -> LockGuard < ' _ , FxHashMap < usize , ( AllocId , bool ) > > ,
219
+ LocalCache : FnOnce ( & mut D ) -> & mut FxHashSet < AllocId > ,
218
220
> (
219
221
decoder : & mut D ,
220
222
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
221
- cache : CACHE ,
223
+ mut global_cache : GlobalCache ,
224
+ local_cache : LocalCache ,
222
225
) -> Result < AllocId , D :: Error > {
226
+ let pos = decoder. position ( ) ;
223
227
match AllocKind :: decode ( decoder) ? {
224
228
AllocKind :: AllocAtPos => {
225
- let pos = decoder. read_usize ( ) ?;
226
- if let Some ( alloc_id) = cache ( decoder) . get ( & pos) . cloned ( ) {
227
- return Ok ( alloc_id) ;
228
- }
229
- decoder. with_position ( pos, AllocId :: decode)
229
+ let real_pos = decoder. read_usize ( ) ?;
230
+ decoder. with_position ( real_pos, AllocId :: decode)
230
231
} ,
231
232
AllocKind :: Alloc => {
232
- let pos = decoder. position ( ) ;
233
- // insert early to allow recursive allocs
234
- let alloc_id = * cache ( decoder) . entry ( pos)
235
- . or_insert_with ( || tcx. alloc_map . lock ( ) . reserve ( ) ) ;
236
- trace ! ( "creating alloc id {:?}" , alloc_id) ;
233
+ let alloc_id = {
234
+ let mut cache = global_cache ( decoder) ;
235
+ let entry = cache. entry ( pos) ;
236
+ match entry {
237
+ Entry :: Occupied ( occupied) => {
238
+ let id = occupied. get ( ) . 0 ;
239
+
240
+ // If the alloc id is fully loaded we just return here.
241
+ if occupied. get ( ) . 1 {
242
+ return Ok ( id)
243
+ }
244
+
245
+ // It was only partially loaded.
246
+ // This may be loading further up the stack
247
+ // or concurrently in another thread.
248
+ id
249
+ }
250
+ Entry :: Vacant ( vacant) => {
251
+ // Insert early to allow recursive allocs
252
+ let id = tcx. alloc_map . lock ( ) . reserve ( ) ;
253
+ vacant. insert ( ( id, false ) ) ;
254
+ id
255
+ }
256
+ }
257
+ } ;
258
+
259
+ // Insert early to allow recursive allocs and ot indicate that the current
260
+ // session will eventually fully load this alloc id
261
+ if !local_cache ( decoder) . insert ( alloc_id) {
262
+ // We have started decoding this alloc id already, so just return it.
263
+ // Its content is already filled in or will be filled in by functions
264
+ // further up the stack.
265
+ return Ok ( alloc_id) ;
266
+
267
+ }
237
268
238
269
let allocation = <& ' tcx Allocation as Decodable >:: decode ( decoder) ?;
239
270
trace ! ( "decoded alloc {:?} {:#?}" , alloc_id, allocation) ;
240
271
// This may overwrite with the same allocation
241
272
tcx. alloc_map . lock ( ) . set_id_same_memory ( alloc_id, allocation) ;
242
273
274
+ // Mark the alloc id as fully loaded
275
+ global_cache ( decoder) . insert ( pos, ( alloc_id, true ) ) ;
276
+
243
277
Ok ( alloc_id)
244
278
} ,
245
279
AllocKind :: Fn => {
0 commit comments