From 24a40da1d4caf5b2c643fefa3751f73dfbab9e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 7 May 2018 23:38:03 +0200 Subject: [PATCH 1/4] Make AllocId decoding thread-safe --- src/librustc/mir/interpret/mod.rs | 47 +++++++++---- src/librustc/ty/maps/on_disk_cache.rs | 95 +++++---------------------- src/librustc_metadata/decoder.rs | 41 +++--------- src/librustc_metadata/encoder.rs | 50 ++------------ src/librustc_metadata/schema.rs | 1 - 5 files changed, 68 insertions(+), 166 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 48954b1f0aa7e..7b8d465456ca2 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -17,15 +17,17 @@ use mir; use hir::def_id::DefId; use ty::{self, TyCtxt, Instance}; use ty::layout::{self, Align, HasDataLayout, Size}; +use ty::codec::{TyEncoder, TyDecoder}; use middle::region; use std::iter; use std::io; use std::ops::{Deref, DerefMut}; use std::hash::Hash; use syntax::ast::Mutability; -use rustc_serialize::{Encoder, Decoder, Decodable, Encodable}; +use rustc_serialize::{Decodable, Encodable}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{HashMapExt, LockGuard}; use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] @@ -162,25 +164,37 @@ impl ::rustc_serialize::UseSpecializedDecodable for AllocId {} #[derive(RustcDecodable, RustcEncodable)] enum AllocKind { Alloc, + AllocAtPos, Fn, Static, } pub fn specialized_encode_alloc_id< 'a, 'tcx, - E: Encoder, + E: TyEncoder, + M, >( encoder: &mut E, tcx: TyCtxt<'a, 'tcx, 'tcx>, + cache: M, alloc_id: AllocId, -) -> Result<(), E::Error> { +) -> Result<(), E::Error> +where + M: Fn(&mut E) -> &mut FxHashMap +{ let alloc_type: AllocType<'tcx, &'tcx Allocation> = tcx.alloc_map.lock().get(alloc_id).expect("no value for AllocId"); match alloc_type { AllocType::Memory(alloc) => { + if let Some(alloc_pos) = cache(encoder).get(&alloc_id).cloned() { + AllocKind::AllocAtPos.encode(encoder)?; + return encoder.emit_usize(alloc_pos); + } + let pos = encoder.position(); trace!("encoding {:?} with {:#?}", alloc_id, alloc); AllocKind::Alloc.encode(encoder)?; alloc.encode(encoder)?; + cache(encoder).insert_same(alloc_id, pos); } AllocType::Function(fn_instance) => { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); @@ -199,23 +213,32 @@ pub fn specialized_encode_alloc_id< pub fn specialized_decode_alloc_id< 'a, 'tcx, - D: Decoder, - CACHE: FnOnce(&mut D, AllocId), + D: TyDecoder<'a, 'tcx>, + CACHE: FnOnce(&mut D) -> LockGuard<'_, FxHashMap>, >( decoder: &mut D, tcx: TyCtxt<'a, 'tcx, 'tcx>, cache: CACHE, ) -> Result { match AllocKind::decode(decoder)? { + AllocKind::AllocAtPos => { + let pos = decoder.read_usize()?; + if let Some(alloc_id) = cache(decoder).get(&pos).cloned() { + return Ok(alloc_id); + } + decoder.with_position(pos, AllocId::decode) + }, AllocKind::Alloc => { - let alloc_id = tcx.alloc_map.lock().reserve(); - trace!("creating alloc id {:?}", alloc_id); + let pos = decoder.position(); // insert early to allow recursive allocs - cache(decoder, alloc_id); + let alloc_id = *cache(decoder).entry(pos) + .or_insert_with(|| tcx.alloc_map.lock().reserve()); + trace!("creating alloc id {:?}", alloc_id); let allocation = <&'tcx Allocation as Decodable>::decode(decoder)?; trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); - tcx.alloc_map.lock().set_id_memory(alloc_id, allocation); + // This may overwrite with the same allocation + tcx.alloc_map.lock().set_id_same_memory(alloc_id, allocation); Ok(alloc_id) }, @@ -225,14 +248,12 @@ pub fn specialized_decode_alloc_id< trace!("decoded fn alloc instance: {:?}", instance); let id = tcx.alloc_map.lock().create_fn_alloc(instance); trace!("created fn alloc id: {:?}", id); - cache(decoder, id); Ok(id) }, AllocKind::Static => { trace!("creating extern static alloc id at"); let did = DefId::decode(decoder)?; let alloc_id = tcx.alloc_map.lock().intern_static(did); - cache(decoder, alloc_id); Ok(alloc_id) }, } @@ -333,6 +354,10 @@ impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> { bug!("tried to set allocation id {}, but it was already existing as {:#?}", id, old); } } + + fn set_id_same_memory(&mut self, id: AllocId, mem: M) { + self.id_to_type.insert_same(id, AllocType::Memory(mem)); + } } #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 9ca90a06c4e50..0cc25933aed94 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -23,7 +23,6 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, SpecializedDecoder, SpecializedEncoder, UseSpecializedDecodable, UseSpecializedEncodable}; use session::{CrateDisambiguator, Session}; -use std::cell::RefCell; use std::mem; use syntax::ast::NodeId; use syntax::codemap::{CodeMap, StableFilemapId}; @@ -77,11 +76,8 @@ pub struct OnDiskCache<'sess> { // `serialized_data`. prev_diagnostics_index: FxHashMap, - // Alloc indices to memory location map - prev_interpret_alloc_index: Vec, - /// Deserialization: A cache to ensure we don't read allocations twice - interpret_alloc_cache: RefCell>, + interpret_alloc_cache: Lock>, } // This type is used only for (de-)serialization. @@ -91,8 +87,6 @@ struct Footer { prev_cnums: Vec<(u32, String, CrateDisambiguator)>, query_result_index: EncodedQueryResultIndex, diagnostics_index: EncodedQueryResultIndex, - // the location of all allocations - interpret_alloc_index: Vec, } type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; @@ -149,8 +143,7 @@ impl<'sess> OnDiskCache<'sess> { query_result_index: footer.query_result_index.into_iter().collect(), prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), synthetic_expansion_infos: Lock::new(FxHashMap()), - prev_interpret_alloc_index: footer.interpret_alloc_index, - interpret_alloc_cache: RefCell::new(FxHashMap::default()), + interpret_alloc_cache: Lock::new(FxHashMap::default()), } } @@ -166,8 +159,7 @@ impl<'sess> OnDiskCache<'sess> { query_result_index: FxHashMap(), prev_diagnostics_index: FxHashMap(), synthetic_expansion_infos: Lock::new(FxHashMap()), - prev_interpret_alloc_index: Vec::new(), - interpret_alloc_cache: RefCell::new(FxHashMap::default()), + interpret_alloc_cache: Lock::new(FxHashMap::default()), } } @@ -201,7 +193,6 @@ impl<'sess> OnDiskCache<'sess> { predicate_shorthands: FxHashMap(), expn_info_shorthands: FxHashMap(), interpret_allocs: FxHashMap(), - interpret_allocs_inverse: Vec::new(), codemap: CachingCodemapView::new(tcx.sess.codemap()), file_to_file_index, }; @@ -279,31 +270,6 @@ impl<'sess> OnDiskCache<'sess> { diagnostics_index }; - let interpret_alloc_index = { - let mut interpret_alloc_index = Vec::new(); - let mut n = 0; - loop { - let new_n = encoder.interpret_allocs_inverse.len(); - // if we have found new ids, serialize those, too - if n == new_n { - // otherwise, abort - break; - } - for idx in n..new_n { - let id = encoder.interpret_allocs_inverse[idx]; - let pos = AbsoluteBytePos::new(encoder.position()); - interpret_alloc_index.push(pos); - interpret::specialized_encode_alloc_id( - &mut encoder, - tcx, - id, - )?; - } - n = new_n; - } - interpret_alloc_index - }; - let sorted_cnums = sorted_cnums_including_local_crate(tcx); let prev_cnums: Vec<_> = sorted_cnums.iter().map(|&cnum| { let crate_name = tcx.original_crate_name(cnum).as_str().to_string(); @@ -318,7 +284,6 @@ impl<'sess> OnDiskCache<'sess> { prev_cnums, query_result_index, diagnostics_index, - interpret_alloc_index, })?; // Encode the position of the footer as the last 8 bytes of the @@ -424,7 +389,6 @@ impl<'sess> OnDiskCache<'sess> { file_index_to_file: &self.file_index_to_file, file_index_to_stable_id: &self.file_index_to_stable_id, synthetic_expansion_infos: &self.synthetic_expansion_infos, - prev_interpret_alloc_index: &self.prev_interpret_alloc_index, interpret_alloc_cache: &self.interpret_alloc_cache, }; @@ -487,9 +451,7 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { synthetic_expansion_infos: &'x Lock>, file_index_to_file: &'x Lock>>, file_index_to_stable_id: &'x FxHashMap, - interpret_alloc_cache: &'x RefCell>, - /// maps from index in the cache file to location in the cache file - prev_interpret_alloc_index: &'x [AbsoluteBytePos], + interpret_alloc_cache: &'x Lock>, } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { @@ -613,31 +575,14 @@ implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { let tcx = self.tcx; - let idx = usize::decode(self)?; - trace!("loading index {}", idx); - - if let Some(cached) = self.interpret_alloc_cache.borrow().get(&idx).cloned() { - trace!("loading alloc id {:?} from alloc_cache", cached); - return Ok(cached); - } - let pos = self.prev_interpret_alloc_index[idx].to_usize(); - trace!("loading position {}", pos); - self.with_position(pos, |this| { - interpret::specialized_decode_alloc_id( - this, - tcx, - |this, alloc_id| { - trace!("caching idx {} for alloc id {} at position {}", idx, alloc_id, pos); - assert!(this - .interpret_alloc_cache - .borrow_mut() - .insert(idx, alloc_id) - .is_none()); - }, - ) - }) + interpret::specialized_decode_alloc_id( + self, + tcx, + |this| this.interpret_alloc_cache.lock(), + ) } } + impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { let tag: u8 = Decodable::decode(self)?; @@ -800,7 +745,6 @@ struct CacheEncoder<'enc, 'a, 'tcx, E> predicate_shorthands: FxHashMap, usize>, expn_info_shorthands: FxHashMap, interpret_allocs: FxHashMap, - interpret_allocs_inverse: Vec, codemap: CachingCodemapView<'tcx>, file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>, } @@ -837,18 +781,13 @@ impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder< where E: 'enc + ty_codec::TyEncoder { fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { - use std::collections::hash_map::Entry; - let index = match self.interpret_allocs.entry(*alloc_id) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let idx = self.interpret_allocs_inverse.len(); - self.interpret_allocs_inverse.push(*alloc_id); - e.insert(idx); - idx - }, - }; - - index.encode(self) + let tcx = self.tcx; + interpret::specialized_encode_alloc_id( + self, + tcx, + |this| &mut this.interpret_allocs, + *alloc_id, + ) } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 8af4649ed5f40..a6515c2e5522a 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -13,7 +13,7 @@ use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule}; use schema::*; -use rustc_data_structures::sync::{Lrc, ReadGuard}; +use rustc_data_structures::sync::{Lrc, ReadGuard, Lock}; use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash, DisambiguatedDefPathData}; use rustc::hir; @@ -56,10 +56,7 @@ pub struct DecodeContext<'a, 'tcx: 'a> { lazy_state: LazyState, // interpreter allocation cache - interpret_alloc_cache: FxHashMap, - - // Read from the LazySeq CrateRoot::inpterpret_alloc_index on demand - interpret_alloc_index: Option>, + interpret_alloc_cache: Lock>, } /// Abstract over the various ways one can create metadata decoders. @@ -78,8 +75,7 @@ pub trait Metadata<'a, 'tcx>: Copy { tcx, last_filemap_index: 0, lazy_state: LazyState::NoNode, - interpret_alloc_cache: FxHashMap::default(), - interpret_alloc_index: None, + interpret_alloc_cache: Lock::new(FxHashMap::default()), } } } @@ -178,17 +174,6 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { self.lazy_state = LazyState::Previous(position + min_size); Ok(position) } - - fn interpret_alloc(&mut self, idx: usize) -> usize { - if let Some(index) = self.interpret_alloc_index.as_mut() { - return index[idx] as usize; - } - let cdata = self.cdata(); - let index: Vec = cdata.root.interpret_alloc_index.decode(cdata).collect(); - let pos = index[idx]; - self.interpret_alloc_index = Some(index); - pos as usize - } } impl<'a, 'tcx: 'a> TyDecoder<'a, 'tcx> for DecodeContext<'a, 'tcx> { @@ -300,21 +285,11 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { let tcx = self.tcx.unwrap(); - let idx = usize::decode(self)?; - - if let Some(cached) = self.interpret_alloc_cache.get(&idx).cloned() { - return Ok(cached); - } - let pos = self.interpret_alloc(idx); - self.with_position(pos, |this| { - interpret::specialized_decode_alloc_id( - this, - tcx, - |this, alloc_id| { - assert!(this.interpret_alloc_cache.insert(idx, alloc_id).is_none()); - }, - ) - }) + interpret::specialized_decode_alloc_id( + self, + tcx, + |this| this.interpret_alloc_cache.lock() + ) } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ab30ff7f072b7..b1adc9c48103f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -61,7 +61,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> { predicate_shorthands: FxHashMap, usize>, interpret_allocs: FxHashMap, - interpret_allocs_inverse: Vec, // This is used to speed up Span encoding. filemap_cache: Lrc, @@ -198,18 +197,13 @@ impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { - use std::collections::hash_map::Entry; - let index = match self.interpret_allocs.entry(*alloc_id) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let idx = self.interpret_allocs_inverse.len(); - self.interpret_allocs_inverse.push(*alloc_id); - e.insert(idx); - idx - }, - }; - - index.encode(self) + let tcx = self.tcx; + interpret::specialized_encode_alloc_id( + self, + tcx, + |this| &mut this.interpret_allocs, + *alloc_id, + ) } } @@ -450,34 +444,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let items = self.encode_info_for_items(); let item_bytes = self.position() - i; - // Encode the allocation index - let interpret_alloc_index = { - let mut interpret_alloc_index = Vec::new(); - let mut n = 0; - trace!("beginning to encode alloc ids"); - loop { - let new_n = self.interpret_allocs_inverse.len(); - // if we have found new ids, serialize those, too - if n == new_n { - // otherwise, abort - break; - } - trace!("encoding {} further alloc ids", new_n - n); - for idx in n..new_n { - let id = self.interpret_allocs_inverse[idx]; - let pos = self.position() as u32; - interpret_alloc_index.push(pos); - interpret::specialized_encode_alloc_id( - self, - tcx, - id, - ).unwrap(); - } - n = new_n; - } - self.lazy_seq(interpret_alloc_index) - }; - // Index the items i = self.position(); let index = items.write_index(&mut self.opaque.cursor); @@ -529,7 +495,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { impls, exported_symbols, wasm_custom_sections, - interpret_alloc_index, index, }); @@ -1823,7 +1788,6 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, predicate_shorthands: Default::default(), filemap_cache: tcx.sess.codemap().files()[0].clone(), interpret_allocs: Default::default(), - interpret_allocs_inverse: Default::default(), }; // Encode the rustc version string in a predictable location. diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 2e89ea6d2c121..70e052ccc96e7 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -207,7 +207,6 @@ pub struct CrateRoot { pub impls: LazySeq, pub exported_symbols: EncodedExportedSymbols, pub wasm_custom_sections: LazySeq, - pub interpret_alloc_index: LazySeq, pub index: LazySeq, From 94eef3492be61535450ca82065a522832afb646a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 23 May 2018 06:46:13 +0200 Subject: [PATCH 2/4] Fixes --- src/librustc/mir/interpret/mod.rs | 62 +++++++++++++++++++++------ src/librustc/ty/maps/on_disk_cache.rs | 9 ++-- src/librustc_metadata/decoder.rs | 9 ++-- 3 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 7b8d465456ca2..c400a44b1f7f0 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -12,6 +12,7 @@ pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage}; pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue}; +use std::collections::hash_map::Entry; use std::fmt; use mir; use hir::def_id::DefId; @@ -26,7 +27,7 @@ use std::hash::Hash; use syntax::ast::Mutability; use rustc_serialize::{Decodable, Encodable}; use rustc_data_structures::sorted_map::SortedMap; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{HashMapExt, LockGuard}; use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; @@ -191,10 +192,10 @@ where return encoder.emit_usize(alloc_pos); } let pos = encoder.position(); + assert!(cache(encoder).insert(alloc_id, pos).is_none()); trace!("encoding {:?} with {:#?}", alloc_id, alloc); AllocKind::Alloc.encode(encoder)?; alloc.encode(encoder)?; - cache(encoder).insert_same(alloc_id, pos); } AllocType::Function(fn_instance) => { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); @@ -214,32 +215,65 @@ where pub fn specialized_decode_alloc_id< 'a, 'tcx, D: TyDecoder<'a, 'tcx>, - CACHE: FnOnce(&mut D) -> LockGuard<'_, FxHashMap>, + GlobalCache: FnMut(&mut D) -> LockGuard<'_, FxHashMap>, + LocalCache: FnOnce(&mut D) -> &mut FxHashSet, >( decoder: &mut D, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cache: CACHE, + mut global_cache: GlobalCache, + local_cache: LocalCache, ) -> Result { + let pos = decoder.position(); match AllocKind::decode(decoder)? { AllocKind::AllocAtPos => { - let pos = decoder.read_usize()?; - if let Some(alloc_id) = cache(decoder).get(&pos).cloned() { - return Ok(alloc_id); - } - decoder.with_position(pos, AllocId::decode) + let real_pos = decoder.read_usize()?; + decoder.with_position(real_pos, AllocId::decode) }, AllocKind::Alloc => { - let pos = decoder.position(); - // insert early to allow recursive allocs - let alloc_id = *cache(decoder).entry(pos) - .or_insert_with(|| tcx.alloc_map.lock().reserve()); - trace!("creating alloc id {:?}", alloc_id); + let alloc_id = { + let mut cache = global_cache(decoder); + let entry = cache.entry(pos); + match entry { + Entry::Occupied(occupied) => { + let id = occupied.get().0; + + // If the alloc id is fully loaded we just return here. + if occupied.get().1 { + return Ok(id) + } + + // It was only partially loaded. + // This may be loading further up the stack + // or concurrently in another thread. + id + } + Entry::Vacant(vacant) => { + // Insert early to allow recursive allocs + let id = tcx.alloc_map.lock().reserve(); + vacant.insert((id, false)); + id + } + } + }; + + // Insert early to allow recursive allocs and ot indicate that the current + // session will eventually fully load this alloc id + if !local_cache(decoder).insert(alloc_id) { + // We have started decoding this alloc id already, so just return it. + // Its content is already filled in or will be filled in by functions + // further up the stack. + return Ok(alloc_id); + + } let allocation = <&'tcx Allocation as Decodable>::decode(decoder)?; trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); // This may overwrite with the same allocation tcx.alloc_map.lock().set_id_same_memory(alloc_id, allocation); + // Mark the alloc id as fully loaded + global_cache(decoder).insert(pos, (alloc_id, true)); + Ok(alloc_id) }, AllocKind::Fn => { diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 0cc25933aed94..f9d41e32838cc 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -16,7 +16,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, use hir::map::definitions::DefPathHash; use ich::{CachingCodemapView, Fingerprint}; use mir::{self, interpret}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, @@ -77,7 +77,7 @@ pub struct OnDiskCache<'sess> { prev_diagnostics_index: FxHashMap, /// Deserialization: A cache to ensure we don't read allocations twice - interpret_alloc_cache: Lock>, + interpret_alloc_cache: Lock>, } // This type is used only for (de-)serialization. @@ -390,6 +390,7 @@ impl<'sess> OnDiskCache<'sess> { file_index_to_stable_id: &self.file_index_to_stable_id, synthetic_expansion_infos: &self.synthetic_expansion_infos, interpret_alloc_cache: &self.interpret_alloc_cache, + interpret_alloc_local_cache: FxHashSet::default(), }; match decode_tagged(&mut decoder, dep_node_index) { @@ -451,7 +452,8 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { synthetic_expansion_infos: &'x Lock>, file_index_to_file: &'x Lock>>, file_index_to_stable_id: &'x FxHashMap, - interpret_alloc_cache: &'x Lock>, + interpret_alloc_cache: &'x Lock>, + interpret_alloc_local_cache: FxHashSet, } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { @@ -579,6 +581,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, ' self, tcx, |this| this.interpret_alloc_cache.lock(), + |this| &mut this.interpret_alloc_local_cache, ) } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index a6515c2e5522a..b28b7b54b325c 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -30,7 +30,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::codec::TyDecoder; use rustc::mir::Mir; use rustc::util::captures::Captures; -use rustc::util::nodemap::FxHashMap; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; use std::io; use std::mem; @@ -56,7 +56,8 @@ pub struct DecodeContext<'a, 'tcx: 'a> { lazy_state: LazyState, // interpreter allocation cache - interpret_alloc_cache: Lock>, + interpret_alloc_cache: Lock>, + interpret_alloc_local_cache: FxHashSet, } /// Abstract over the various ways one can create metadata decoders. @@ -76,6 +77,7 @@ pub trait Metadata<'a, 'tcx>: Copy { last_filemap_index: 0, lazy_state: LazyState::NoNode, interpret_alloc_cache: Lock::new(FxHashMap::default()), + interpret_alloc_local_cache: FxHashSet::default(), } } } @@ -288,7 +290,8 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx interpret::specialized_decode_alloc_id( self, tcx, - |this| this.interpret_alloc_cache.lock() + |this| this.interpret_alloc_cache.lock(), + |this| &mut this.interpret_alloc_local_cache, ) } } From 398d282be7174c23f48f85dc407731526c644d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 25 May 2018 07:26:47 +0200 Subject: [PATCH 3/4] Encode the allocation size so we can skip ahead --- src/librustc/mir/interpret/mod.rs | 60 +++++++++++++-------------- src/librustc/ty/codec.rs | 7 ++++ src/librustc/ty/maps/on_disk_cache.rs | 9 ++++ src/librustc_metadata/decoder.rs | 5 +++ src/librustc_metadata/encoder.rs | 3 ++ 5 files changed, 52 insertions(+), 32 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index c400a44b1f7f0..9e314d53189f9 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -12,7 +12,6 @@ pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage}; pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue}; -use std::collections::hash_map::Entry; use std::fmt; use mir; use hir::def_id::DefId; @@ -195,7 +194,21 @@ where assert!(cache(encoder).insert(alloc_id, pos).is_none()); trace!("encoding {:?} with {:#?}", alloc_id, alloc); AllocKind::Alloc.encode(encoder)?; + + // Write placeholder for size + let size_pos = encoder.position(); + 0usize.encode(encoder)?; + + let start = encoder.position(); alloc.encode(encoder)?; + let end = encoder.position(); + + // Overwrite the placeholder with the real size + let size: usize = end - start; + encoder.set_position(size_pos); + size.encode(encoder)?; + encoder.set_position(end); + } AllocType::Function(fn_instance) => { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); @@ -230,40 +243,23 @@ pub fn specialized_decode_alloc_id< decoder.with_position(real_pos, AllocId::decode) }, AllocKind::Alloc => { - let alloc_id = { - let mut cache = global_cache(decoder); - let entry = cache.entry(pos); - match entry { - Entry::Occupied(occupied) => { - let id = occupied.get().0; - - // If the alloc id is fully loaded we just return here. - if occupied.get().1 { - return Ok(id) - } - - // It was only partially loaded. - // This may be loading further up the stack - // or concurrently in another thread. - id - } - Entry::Vacant(vacant) => { - // Insert early to allow recursive allocs - let id = tcx.alloc_map.lock().reserve(); - vacant.insert((id, false)); - id - } - } - }; - - // Insert early to allow recursive allocs and ot indicate that the current - // session will eventually fully load this alloc id - if !local_cache(decoder).insert(alloc_id) { + // Read the size of the allocation. + // Used to skip ahead if we don't need to decode this. + let alloc_size = usize::decode(decoder)?; + + let (alloc_id, fully_loaded) = *global_cache(decoder).entry(pos).or_insert_with(|| { + // Create an id which is not fully loaded + (tcx.alloc_map.lock().reserve(), false) + }); + if fully_loaded || !local_cache(decoder).insert(alloc_id) { // We have started decoding this alloc id already, so just return it. // Its content is already filled in or will be filled in by functions // further up the stack. - return Ok(alloc_id); - + + // Skip the allocation + let pos = decoder.position(); + decoder.set_position(pos + alloc_size); + return Ok(alloc_id) } let allocation = <&'tcx Allocation as Decodable>::decode(decoder)?; diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index d911f32ed3f1f..822d6f7914910 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -52,6 +52,7 @@ impl<'tcx> EncodableWithShorthand for ty::Predicate<'tcx> { pub trait TyEncoder: Encoder { fn position(&self) -> usize; + fn set_position(&mut self, usize); } impl<'buf> TyEncoder for opaque::Encoder<'buf> { @@ -59,6 +60,10 @@ impl<'buf> TyEncoder for opaque::Encoder<'buf> { fn position(&self) -> usize { self.position() } + #[inline] + fn set_position(&mut self, p: usize) { + self.cursor.set_position(p as u64) + } } /// Encode the given value or a previously cached shorthand. @@ -123,6 +128,8 @@ pub trait TyDecoder<'a, 'tcx: 'a>: Decoder { fn position(&self) -> usize; + fn set_position(&mut self, usize); + fn cached_ty_for_shorthand(&mut self, shorthand: usize, or_insert_with: F) diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index f9d41e32838cc..8a85f75fdd374 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -525,6 +525,11 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, self.opaque.position() } + #[inline] + fn set_position(&mut self, p: usize) { + self.opaque.set_position(p) + } + #[inline] fn peek_byte(&self) -> u8 { self.opaque.data[self.opaque.position()] @@ -860,6 +865,10 @@ impl<'enc, 'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'enc, 'a, 'tcx, E> fn position(&self) -> usize { self.encoder.position() } + #[inline] + fn set_position(&mut self, p: usize) { + self.encoder.set_position(p) + } } impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b28b7b54b325c..6dab3e2aadd05 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -195,6 +195,11 @@ impl<'a, 'tcx: 'a> TyDecoder<'a, 'tcx> for DecodeContext<'a, 'tcx> { self.opaque.position() } + #[inline] + fn set_position(&mut self, p: usize) { + self.opaque.set_position(p) + } + fn cached_ty_for_shorthand(&mut self, shorthand: usize, or_insert_with: F) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index b1adc9c48103f..18df354b8492d 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -234,6 +234,9 @@ impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { fn position(&self) -> usize { self.opaque.position() } + fn set_position(&mut self, p: usize) { + self.opaque.set_position(p) + } } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { From 4adcc57b4ff5bce182948c42673e196235768ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 25 May 2018 13:35:32 +0200 Subject: [PATCH 4/4] Encode sizes using arrays --- src/librustc/mir/interpret/mod.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 9e314d53189f9..ff357ceac3490 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -12,6 +12,7 @@ pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage}; pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue}; +use std; use std::fmt; use mir; use hir::def_id::DefId; @@ -28,7 +29,7 @@ use rustc_serialize::{Decodable, Encodable}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{HashMapExt, LockGuard}; -use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; +use byteorder::{ByteOrder, WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum Lock { @@ -197,7 +198,7 @@ where // Write placeholder for size let size_pos = encoder.position(); - 0usize.encode(encoder)?; + [0; 4].encode(encoder)?; let start = encoder.position(); alloc.encode(encoder)?; @@ -206,7 +207,10 @@ where // Overwrite the placeholder with the real size let size: usize = end - start; encoder.set_position(size_pos); - size.encode(encoder)?; + assert!(size as u64 <= std::u32::MAX as u64); + let mut size_array = [0; 4]; + LittleEndian::write_u32(&mut size_array, size as u32); + size_array.encode(encoder)?; encoder.set_position(end); } @@ -245,7 +249,13 @@ pub fn specialized_decode_alloc_id< AllocKind::Alloc => { // Read the size of the allocation. // Used to skip ahead if we don't need to decode this. - let alloc_size = usize::decode(decoder)?; + let alloc_size = [ + u8::decode(decoder)?, + u8::decode(decoder)?, + u8::decode(decoder)?, + u8::decode(decoder)? + ]; + let alloc_size = LittleEndian::read_u32(&alloc_size); let (alloc_id, fully_loaded) = *global_cache(decoder).entry(pos).or_insert_with(|| { // Create an id which is not fully loaded @@ -258,7 +268,7 @@ pub fn specialized_decode_alloc_id< // Skip the allocation let pos = decoder.position(); - decoder.set_position(pos + alloc_size); + decoder.set_position(pos + alloc_size as usize); return Ok(alloc_id) }