From 2546ff8cb226d4bc67e7f6f8884f418cd31e56ea Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 10 Apr 2018 09:58:46 +0200 Subject: [PATCH 01/15] Don't recurse into allocations, use a global table instead --- src/librustc/ich/impls_ty.rs | 24 +++-- src/librustc/mir/interpret/mod.rs | 48 ++++----- src/librustc/ty/maps/on_disk_cache.rs | 135 ++++++++++++++----------- src/librustc_metadata/decoder.rs | 49 ++++----- src/librustc_metadata/encoder.rs | 68 +++++++++---- src/librustc_metadata/schema.rs | 1 + src/test/incremental/static_cycle/b.rs | 19 ++++ 7 files changed, 192 insertions(+), 152 deletions(-) create mode 100644 src/test/incremental/static_cycle/b.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index db9fc005f2175..7b0853f40c4e8 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -380,12 +380,12 @@ impl_stable_hash_for!(struct mir::interpret::MemoryPointer { enum AllocDiscriminant { Alloc, - ExternStatic, + Static, Function, } impl_stable_hash_for!(enum self::AllocDiscriminant { Alloc, - ExternStatic, + Static, Function }); @@ -396,24 +396,26 @@ impl<'a> HashStable> for mir::interpret::AllocId { hasher: &mut StableHasher, ) { ty::tls::with_opt(|tcx| { + trace!("hashing {:?}", *self); let tcx = tcx.expect("can't hash AllocIds during hir lowering"); - if let Some(alloc) = tcx.interpret_interner.get_alloc(*self) { + if let Some(def_id) = tcx.interpret_interner + .get_corresponding_static_def_id(*self) { + AllocDiscriminant::Static.hash_stable(hcx, hasher); + trace!("hashing {:?} as static {:?}", *self, def_id); + def_id.hash_stable(hcx, hasher); + } else if let Some(alloc) = tcx.interpret_interner.get_alloc(*self) { AllocDiscriminant::Alloc.hash_stable(hcx, hasher); if hcx.alloc_id_recursion_tracker.insert(*self) { - tcx - .interpret_interner - .get_corresponding_static_def_id(*self) - .hash_stable(hcx, hasher); + trace!("hashing {:?} as alloc {:#?}", *self, alloc); alloc.hash_stable(hcx, hasher); assert!(hcx.alloc_id_recursion_tracker.remove(self)); + } else { + trace!("skipping hashing of {:?} due to recursion", *self); } } else if let Some(inst) = tcx.interpret_interner.get_fn(*self) { + trace!("hashing {:?} as fn {:#?}", *self, inst); AllocDiscriminant::Function.hash_stable(hcx, hasher); inst.hash_stable(hcx, hasher); - } else if let Some(def_id) = tcx.interpret_interner - .get_corresponding_static_def_id(*self) { - AllocDiscriminant::ExternStatic.hash_stable(hcx, hasher); - def_id.hash_stable(hcx, hasher); } else { bug!("no allocation for {}", self); } diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index e242ec4985ab4..9003cca815ee3 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -154,10 +154,12 @@ pub struct AllocId(pub u64); impl ::rustc_serialize::UseSpecializedEncodable for AllocId {} impl ::rustc_serialize::UseSpecializedDecodable for AllocId {} -pub const ALLOC_DISCRIMINANT: usize = 0; -pub const FN_DISCRIMINANT: usize = 1; -pub const EXTERN_STATIC_DISCRIMINANT: usize = 2; -pub const SHORTHAND_START: usize = 3; +#[derive(RustcDecodable, RustcEncodable)] +enum AllocKind { + Alloc, + Fn, + ExternStatic, +} pub fn specialized_encode_alloc_id< 'a, 'tcx, @@ -166,14 +168,10 @@ pub fn specialized_encode_alloc_id< encoder: &mut E, tcx: TyCtxt<'a, 'tcx, 'tcx>, alloc_id: AllocId, - shorthand: Option, ) -> Result<(), E::Error> { - if let Some(shorthand) = shorthand { - return shorthand.encode(encoder); - } if let Some(alloc) = tcx.interpret_interner.get_alloc(alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, alloc); - ALLOC_DISCRIMINANT.encode(encoder)?; + AllocKind::Alloc.encode(encoder)?; alloc.encode(encoder)?; // encode whether this allocation is the root allocation of a static tcx.interpret_interner @@ -181,11 +179,11 @@ pub fn specialized_encode_alloc_id< .encode(encoder)?; } else if let Some(fn_instance) = tcx.interpret_interner.get_fn(alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); - FN_DISCRIMINANT.encode(encoder)?; + AllocKind::Fn.encode(encoder)?; fn_instance.encode(encoder)?; } else if let Some(did) = tcx.interpret_interner.get_corresponding_static_def_id(alloc_id) { // extern "C" statics don't have allocations, just encode its def_id - EXTERN_STATIC_DISCRIMINANT.encode(encoder)?; + AllocKind::ExternStatic.encode(encoder)?; did.encode(encoder)?; } else { bug!("alloc id without corresponding allocation: {}", alloc_id); @@ -196,21 +194,18 @@ pub fn specialized_encode_alloc_id< pub fn specialized_decode_alloc_id< 'a, 'tcx, D: Decoder, - CACHE: FnOnce(&mut D, usize, AllocId), - SHORT: FnOnce(&mut D, usize) -> Result + CACHE: FnOnce(&mut D, AllocId), >( decoder: &mut D, tcx: TyCtxt<'a, 'tcx, 'tcx>, - pos: usize, cache: CACHE, - short: SHORT, ) -> Result { - match usize::decode(decoder)? { - ALLOC_DISCRIMINANT => { + match AllocKind::decode(decoder)? { + AllocKind::Alloc => { let alloc_id = tcx.interpret_interner.reserve(); - trace!("creating alloc id {:?} at {}", alloc_id, pos); + trace!("creating alloc id {:?}", alloc_id); // insert early to allow recursive allocs - cache(decoder, pos, alloc_id); + cache(decoder, alloc_id); let allocation = Allocation::decode(decoder)?; trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); @@ -223,26 +218,23 @@ pub fn specialized_decode_alloc_id< Ok(alloc_id) }, - FN_DISCRIMINANT => { - trace!("creating fn alloc id at {}", pos); + AllocKind::Fn => { + trace!("creating fn alloc id"); let instance = ty::Instance::decode(decoder)?; trace!("decoded fn alloc instance: {:?}", instance); let id = tcx.interpret_interner.create_fn_alloc(instance); trace!("created fn alloc id: {:?}", id); - cache(decoder, pos, id); + cache(decoder, id); Ok(id) }, - EXTERN_STATIC_DISCRIMINANT => { - trace!("creating extern static alloc id at {}", pos); + AllocKind::ExternStatic => { + trace!("creating extern static alloc id at"); let did = DefId::decode(decoder)?; let alloc_id = tcx.interpret_interner.reserve(); + cache(decoder, alloc_id); tcx.interpret_interner.cache(did, alloc_id); Ok(alloc_id) }, - shorthand => { - trace!("loading shorthand {}", shorthand); - short(decoder, shorthand) - }, } } diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index c103d6e015aa4..7b340ebe784ad 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -76,12 +76,11 @@ pub struct OnDiskCache<'sess> { // `serialized_data`. prev_diagnostics_index: FxHashMap, - // A cache to ensure we don't read allocations twice - interpret_alloc_cache: RefCell>, + // Alloc indices to memory location map + prev_interpret_alloc_index: Vec, - // A map from positions to size of the serialized allocation - // so we can skip over already processed allocations - interpret_alloc_size: RefCell>, + /// Deserialization: A cache to ensure we don't read allocations twice + interpret_alloc_cache: RefCell>, } // This type is used only for (de-)serialization. @@ -91,6 +90,8 @@ 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)>; @@ -147,8 +148,8 @@ 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: RefCell::new(FxHashMap()), + prev_interpret_alloc_index: footer.interpret_alloc_index, interpret_alloc_cache: RefCell::new(FxHashMap::default()), - interpret_alloc_size: RefCell::new(FxHashMap::default()), } } @@ -164,8 +165,8 @@ impl<'sess> OnDiskCache<'sess> { query_result_index: FxHashMap(), prev_diagnostics_index: FxHashMap(), synthetic_expansion_infos: RefCell::new(FxHashMap()), + prev_interpret_alloc_index: Vec::new(), interpret_alloc_cache: RefCell::new(FxHashMap::default()), - interpret_alloc_size: RefCell::new(FxHashMap::default()), } } @@ -198,7 +199,9 @@ impl<'sess> OnDiskCache<'sess> { type_shorthands: FxHashMap(), predicate_shorthands: FxHashMap(), expn_info_shorthands: FxHashMap(), - interpret_alloc_shorthands: FxHashMap(), + interpret_allocs: FxHashMap(), + interpret_alloc_ids: FxHashSet(), + interpret_allocs_inverse: Vec::new(), codemap: CachingCodemapView::new(tcx.sess.codemap()), file_to_file_index, }; @@ -272,6 +275,31 @@ 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_alloc_ids.len(); + 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, + )?; + } + // if we have found new ids, serialize those, too + if n == new_n { + // otherwise, abort + break; + } + 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(); @@ -286,6 +314,7 @@ 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 @@ -393,8 +422,8 @@ 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, - interpret_alloc_size: &self.interpret_alloc_size, }; match decode_tagged(&mut decoder, dep_node_index) { @@ -457,7 +486,8 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { file_index_to_file: &'x RefCell>>, file_index_to_stable_id: &'x FxHashMap, interpret_alloc_cache: &'x RefCell>, - interpret_alloc_size: &'x RefCell>, + /// maps from index in the cache file to location in the cache file + prev_interpret_alloc_index: &'x [AbsoluteBytePos], } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { @@ -580,36 +610,29 @@ 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 pos = TyDecoder::position(self); - trace!("specialized_decode_alloc_id: {:?}", pos); - if let Some(cached) = self.interpret_alloc_cache.borrow().get(&pos).cloned() { - // if there's no end position we are currently deserializing a recursive - // allocation - if let Some(end) = self.interpret_alloc_size.borrow().get(&pos).cloned() { - trace!("{} already cached as {:?}", pos, cached); - // skip ahead - self.opaque.set_position(end); - return Ok(cached) - } + 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 id = interpret::specialized_decode_alloc_id( - self, - tcx, - pos, - |this, pos, alloc_id| { - assert!(this.interpret_alloc_cache.borrow_mut().insert(pos, alloc_id).is_none()); - }, - |this, shorthand| { - // need to load allocation - this.with_position(shorthand, |this| interpret::AllocId::decode(this)) - } - )?; - assert!(self - .interpret_alloc_size - .borrow_mut() - .insert(pos, TyDecoder::position(self)) - .is_none()); - Ok(id) + 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()); + }, + ) + }) } } impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { @@ -773,7 +796,9 @@ struct CacheEncoder<'enc, 'a, 'tcx, E> type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, expn_info_shorthands: FxHashMap, - interpret_alloc_shorthands: FxHashMap, + interpret_allocs: FxHashMap, + interpret_allocs_inverse: Vec, + interpret_alloc_ids: FxHashSet, codemap: CachingCodemapView<'tcx>, file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>, } @@ -810,27 +835,17 @@ 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 tcx = self.tcx; - let pos = self.position(); - let shorthand = match self.interpret_alloc_shorthands.entry(*alloc_id) { - Entry::Occupied(entry) => Some(entry.get().clone()), - Entry::Vacant(entry) => { - // ensure that we don't place any AllocIds at the very beginning - // of the metadata file, because that would end up making our indices - // not special. It is essentially impossible for that to happen, - // but let's make sure - assert!(pos >= interpret::SHORTHAND_START); - entry.insert(pos); - None - }, + let index = if self.interpret_alloc_ids.insert(*alloc_id) { + let idx = self.interpret_alloc_ids.len() - 1; + assert_eq!(idx, self.interpret_allocs_inverse.len()); + self.interpret_allocs_inverse.push(*alloc_id); + assert!(self.interpret_allocs.insert(*alloc_id, idx).is_none()); + idx + } else { + self.interpret_allocs[alloc_id] }; - interpret::specialized_encode_alloc_id( - self, - tcx, - *alloc_id, - shorthand, - ) + + index.encode(self) } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e938d5c1a97fe..2d0037e466cb0 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -59,9 +59,6 @@ pub struct DecodeContext<'a, 'tcx: 'a> { // interpreter allocation cache interpret_alloc_cache: FxHashMap, - // a cache for sizes of interpreter allocations - // needed to skip already deserialized allocations - interpret_alloc_size: FxHashMap, } /// Abstract over the various ways one can create metadata decoders. @@ -81,7 +78,6 @@ pub trait Metadata<'a, 'tcx>: Copy { last_filemap_index: 0, lazy_state: LazyState::NoNode, interpret_alloc_cache: FxHashMap::default(), - interpret_alloc_size: FxHashMap::default(), } } } @@ -290,34 +286,25 @@ 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.expect("need tcx for AllocId decoding"); - let pos = self.position(); - if let Some(cached) = self.interpret_alloc_cache.get(&pos).cloned() { - // if there's no end position we are currently deserializing a recursive - // allocation - if let Some(end) = self.interpret_alloc_size.get(&pos).cloned() { - trace!("{} already cached as {:?}", pos, cached); - // skip ahead - self.opaque.set_position(end); - return Ok(cached) - } + 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 id = interpret::specialized_decode_alloc_id( - self, - tcx, - pos, - |this, pos, alloc_id| { this.interpret_alloc_cache.insert(pos, alloc_id); }, - |this, shorthand| { - // need to load allocation - this.with_position(shorthand, |this| interpret::AllocId::decode(this)) - } - )?; - let end_pos = self.position(); - assert!(self - .interpret_alloc_size - .insert(pos, end_pos) - .is_none()); - Ok(id) + let pos = self + .cdata() + .root + .interpret_alloc_index[idx]; + self.with_position(pos as usize, |this| { + interpret::specialized_decode_alloc_id( + this, + tcx, + |this, alloc_id| { + assert!(this.interpret_alloc_cache.insert(idx, alloc_id).is_none()); + }, + ) + }) } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 39de1ec852ec4..549c5bd760fb9 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -29,7 +29,7 @@ use rustc::ty::{self, Ty, TyCtxt, ReprOptions, SymbolName}; use rustc::ty::codec::{self as ty_codec, TyEncoder}; use rustc::session::config::{self, CrateTypeProcMacro}; -use rustc::util::nodemap::FxHashMap; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; @@ -59,7 +59,10 @@ pub struct EncodeContext<'a, 'tcx: 'a> { lazy_state: LazyState, type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, - interpret_alloc_shorthands: FxHashMap, + + interpret_allocs: FxHashMap, + interpret_allocs_inverse: Vec, + interpret_alloc_ids: FxHashSet, // This is used to speed up Span encoding. filemap_cache: Lrc, @@ -196,26 +199,17 @@ 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 tcx = self.tcx; - let pos = self.position(); - let shorthand = match self.interpret_alloc_shorthands.entry(*alloc_id) { - Entry::Occupied(entry) => Some(entry.get().clone()), - Entry::Vacant(entry) => { - // ensure that we don't place any AllocIds at the very beginning - // of the metadata file, because that would end up making our indices - // not special. This is essentially impossible, but let's make sure - assert!(pos >= interpret::SHORTHAND_START); - entry.insert(pos); - None - }, + let index = if self.interpret_alloc_ids.insert(*alloc_id) { + let idx = self.interpret_alloc_ids.len() - 1; + assert_eq!(idx, self.interpret_allocs_inverse.len()); + self.interpret_allocs_inverse.push(*alloc_id); + assert!(self.interpret_allocs.insert(*alloc_id, idx).is_none()); + idx + } else { + self.interpret_allocs[alloc_id] }; - interpret::specialized_encode_alloc_id( - self, - tcx, - *alloc_id, - shorthand, - ) + + index.encode(self) } } @@ -460,6 +454,33 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let has_default_lib_allocator = attr::contains_name(tcx.hir.krate_attrs(), "default_lib_allocator"); let has_global_allocator = tcx.sess.has_global_allocator.get(); + + // Encode the allocation index + let interpret_alloc_index = { + let mut interpret_alloc_index = Vec::new(); + let mut n = 0; + loop { + let new_n = self.interpret_alloc_ids.len(); + 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(); + } + // if we have found new ids, serialize those, too + if n == new_n { + // otherwise, abort + break; + } + n = new_n; + } + interpret_alloc_index + }; + let root = self.lazy(&CrateRoot { name: tcx.crate_name(LOCAL_CRATE), triple: tcx.sess.opts.target_triple.clone(), @@ -491,6 +512,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { exported_symbols, wasm_custom_sections, index, + interpret_alloc_index, }); let total_bytes = self.position(); @@ -1754,7 +1776,9 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, type_shorthands: Default::default(), predicate_shorthands: Default::default(), filemap_cache: tcx.sess.codemap().files()[0].clone(), - interpret_alloc_shorthands: Default::default(), + interpret_allocs: Default::default(), + interpret_allocs_inverse: Default::default(), + interpret_alloc_ids: 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 d04a4001c5023..d7a766c90c60b 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -207,6 +207,7 @@ pub struct CrateRoot { pub impls: LazySeq, pub exported_symbols: LazySeq<(ExportedSymbol, SymbolExportLevel)>, pub wasm_custom_sections: LazySeq, + pub interpret_alloc_index: Vec, pub index: LazySeq, } diff --git a/src/test/incremental/static_cycle/b.rs b/src/test/incremental/static_cycle/b.rs new file mode 100644 index 0000000000000..b659703bef004 --- /dev/null +++ b/src/test/incremental/static_cycle/b.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions:rpass1 rpass2 + +#![cfg_attr(rpass2, warn(dead_code))] + +pub static mut BAA: *const i8 = unsafe { &BOO as *const _ as *const i8 }; + +pub static mut BOO: *const i8 = unsafe { &BAA as *const _ as *const i8 }; + +fn main() {} From 170ea6500a3643fa673b511a32d32f8f66cbba17 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 10 Apr 2018 16:25:10 +0200 Subject: [PATCH 02/15] Stop referring to statics' AllocIds directly --- src/librustc/ich/impls_ty.rs | 3 +- src/librustc/mir/interpret/mod.rs | 21 +--- src/librustc/ty/context.rs | 39 +++--- src/librustc_mir/interpret/const_eval.rs | 136 +++++---------------- src/librustc_mir/interpret/eval_context.rs | 14 +-- src/librustc_mir/monomorphize/collector.rs | 2 +- src/librustc_trans/mir/constant.rs | 15 ++- 7 files changed, 68 insertions(+), 162 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7b0853f40c4e8..17cbfc7a2c21c 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -398,8 +398,7 @@ impl<'a> HashStable> for mir::interpret::AllocId { ty::tls::with_opt(|tcx| { trace!("hashing {:?}", *self); let tcx = tcx.expect("can't hash AllocIds during hir lowering"); - if let Some(def_id) = tcx.interpret_interner - .get_corresponding_static_def_id(*self) { + if let Some(def_id) = tcx.interpret_interner.get_static(*self) { AllocDiscriminant::Static.hash_stable(hcx, hasher); trace!("hashing {:?} as static {:?}", *self, def_id); def_id.hash_stable(hcx, hasher); diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 9003cca815ee3..07768ac3a3b97 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -158,7 +158,7 @@ impl ::rustc_serialize::UseSpecializedDecodable for AllocId {} enum AllocKind { Alloc, Fn, - ExternStatic, + Static, } pub fn specialized_encode_alloc_id< @@ -173,17 +173,13 @@ pub fn specialized_encode_alloc_id< trace!("encoding {:?} with {:#?}", alloc_id, alloc); AllocKind::Alloc.encode(encoder)?; alloc.encode(encoder)?; - // encode whether this allocation is the root allocation of a static - tcx.interpret_interner - .get_corresponding_static_def_id(alloc_id) - .encode(encoder)?; } else if let Some(fn_instance) = tcx.interpret_interner.get_fn(alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); AllocKind::Fn.encode(encoder)?; fn_instance.encode(encoder)?; - } else if let Some(did) = tcx.interpret_interner.get_corresponding_static_def_id(alloc_id) { - // extern "C" statics don't have allocations, just encode its def_id - AllocKind::ExternStatic.encode(encoder)?; + } else if let Some(did) = tcx.interpret_interner.get_static(alloc_id) { + // referring to statics doesn't need to know about their allocations, just hash the DefId + AllocKind::Static.encode(encoder)?; did.encode(encoder)?; } else { bug!("alloc id without corresponding allocation: {}", alloc_id); @@ -212,10 +208,6 @@ pub fn specialized_decode_alloc_id< let allocation = tcx.intern_const_alloc(allocation); tcx.interpret_interner.intern_at_reserved(alloc_id, allocation); - if let Some(glob) = Option::::decode(decoder)? { - tcx.interpret_interner.cache(glob, alloc_id); - } - Ok(alloc_id) }, AllocKind::Fn => { @@ -227,12 +219,11 @@ pub fn specialized_decode_alloc_id< cache(decoder, id); Ok(id) }, - AllocKind::ExternStatic => { + AllocKind::Static => { trace!("creating extern static alloc id at"); let did = DefId::decode(decoder)?; - let alloc_id = tcx.interpret_interner.reserve(); + let alloc_id = tcx.interpret_interner.cache_static(did); cache(decoder, alloc_id); - tcx.interpret_interner.cache(did, alloc_id); Ok(alloc_id) }, } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fdda2286da03b..b6b38c76a2978 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -935,18 +935,16 @@ struct InterpretInternerInner<'tcx> { /// Allows obtaining const allocs via a unique identifier alloc_by_id: FxHashMap, - /// Reverse map of `alloc_cache` - global_cache: FxHashMap, + /// Allows obtaining static def ids via a unique id + statics: FxHashMap, /// The AllocId to assign to the next new regular allocation. /// Always incremented, never gets smaller. next_id: interpret::AllocId, - /// Allows checking whether a static already has an allocation - /// - /// This is only important for detecting statics referring to themselves - // FIXME(oli-obk) move it to the EvalContext? - alloc_cache: FxHashMap, + /// Inverse map of `statics` + /// Used so we don't allocate a new pointer every time we need one + static_cache: FxHashMap, /// A cache for basic byte allocations keyed by their contents. This is used to deduplicate /// allocations for string and bytestring literals. @@ -980,30 +978,25 @@ impl<'tcx> InterpretInterner<'tcx> { self.inner.borrow().alloc_by_id.get(&id).cloned() } - pub fn get_cached( - &self, - static_id: DefId, - ) -> Option { - self.inner.borrow().alloc_cache.get(&static_id).cloned() - } - - pub fn cache( + pub fn cache_static( &self, static_id: DefId, - alloc_id: interpret::AllocId, - ) { - let mut inner = self.inner.borrow_mut(); - inner.global_cache.insert(alloc_id, static_id); - if let Some(old) = inner.alloc_cache.insert(static_id, alloc_id) { - bug!("tried to cache {:?}, but was already existing as {:#?}", static_id, old); + ) -> interpret::AllocId { + if let Some(alloc_id) = self.inner.borrow().static_cache.get(&static_id).cloned() { + return alloc_id; } + let alloc_id = self.reserve(); + let mut inner = self.inner.borrow_mut(); + inner.static_cache.insert(static_id, alloc_id); + inner.statics.insert(alloc_id, static_id); + alloc_id } - pub fn get_corresponding_static_def_id( + pub fn get_static( &self, ptr: interpret::AllocId, ) -> Option { - self.inner.borrow().global_cache.get(&ptr).cloned() + self.inner.borrow().statics.get(&ptr).cloned() } pub fn intern_at_reserved( diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 57977b6201a61..954a3dbe5b9ab 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -5,7 +5,6 @@ use rustc::mir; use rustc::ty::{self, TyCtxt, Ty, Instance}; use rustc::ty::layout::{self, LayoutOf}; use rustc::ty::subst::Subst; -use rustc::util::nodemap::FxHashSet; use syntax::ast::Mutability; use syntax::codemap::Span; @@ -110,53 +109,38 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( } span = mir.span; let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id()); - let is_static = tcx.is_static(cid.instance.def_id()).is_some(); - let alloc = match alloc { - Some(alloc) => { - assert!(cid.promoted.is_none()); - assert!(param_env.caller_bounds.is_empty()); - alloc - }, - None => { - assert!(!layout.is_unsized()); - let ptr = ecx.memory.allocate( - layout.size.bytes(), - layout.align, - None, - )?; - if is_static { - tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id); - } - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); - let mutability = tcx.is_static(cid.instance.def_id()); - let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::MarkStatic(mutability); - let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); - let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); - trace!("const_eval: pushing stack frame for global: {}{}", name, prom); - assert!(mir.arg_count == 0); - ecx.push_stack_frame( - cid.instance, - mir.span, - mir, - Place::from_ptr(ptr, layout.align), - cleanup, - )?; - - while ecx.step()? {} - ptr.alloc_id - } + assert!(!layout.is_unsized()); + let ptr = ecx.memory.allocate( + layout.size.bytes(), + layout.align, + None, + )?; + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); + let mutability = tcx.is_static(cid.instance.def_id()); + let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { + Mutability::Mutable + } else { + Mutability::Immutable }; - let ptr = MemoryPointer::new(alloc, 0).into(); + let cleanup = StackPopCleanup::MarkStatic(mutability); + let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); + let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); + trace!("const_eval: pushing stack frame for global: {}{}", name, prom); + assert!(mir.arg_count == 0); + ecx.push_stack_frame( + cid.instance, + mir.span, + mir, + Place::from_ptr(ptr, layout.align), + cleanup, + )?; + + while ecx.step()? {} + let ptr = ptr.into(); // always try to read the value and report errors let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { // if it's a constant (so it needs no address, directly compute its value) - Some(val) if !is_static => val, + Some(val) if tcx.is_static(cid.instance.def_id()).is_none() => val, // point at the allocation _ => Value::ByRef(ptr, layout.align), }; @@ -340,21 +324,10 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { - let alloc = ecx - .tcx - .interpret_interner - .get_cached(cid.instance.def_id()); - // Don't evaluate when already cached to prevent cycles - if let Some(alloc) = alloc { - return Ok(alloc) - } - // ensure the static is computed - ecx.const_eval(cid)?; Ok(ecx .tcx .interpret_interner - .get_cached(cid.instance.def_id()) - .expect("uncached static")) + .cache_static(cid.instance.def_id())) } fn box_alloc<'a>( @@ -460,16 +433,7 @@ pub fn const_eval_provider<'a, 'tcx>( let def_id = cid.instance.def.def_id(); if tcx.is_foreign_item(def_id) { - let id = tcx.interpret_interner.get_cached(def_id); - let id = match id { - // FIXME: due to caches this shouldn't happen, add some assertions - Some(id) => id, - None => { - let id = tcx.interpret_interner.reserve(); - tcx.interpret_interner.cache(def_id, id); - id - }, - }; + let id = tcx.interpret_interner.cache_static(def_id); let ty = tcx.type_of(def_id); let layout = tcx.layout_of(key.param_env.and(ty)).unwrap(); let ptr = MemoryPointer::new(id, 0); @@ -505,13 +469,7 @@ pub fn const_eval_provider<'a, 'tcx>( }; let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); - res.map(|(miri_value, ptr, miri_ty)| { - if tcx.is_static(def_id).is_some() { - if let Ok(ptr) = ptr.primval.to_ptr() { - let mut seen = FxHashSet::default(); - create_depgraph_edges(tcx, ptr.alloc_id, &mut seen); - } - } + res.map(|(miri_value, _, miri_ty)| { tcx.mk_const(ty::Const { val: ConstVal::Value(miri_value), ty: miri_ty, @@ -528,35 +486,3 @@ pub fn const_eval_provider<'a, 'tcx>( } }) } - -// This function creates dep graph edges from statics to all referred to statics. -// This is necessary, because the `const_eval` query cannot directly call itself -// for other statics, because we cannot prevent recursion in queries. -// -// see test/incremental/static_refering_to_other_static2/issue.rs for an example -// where not creating those edges would cause static A, which refers to static B -// to point to the old allocation of static B, even though B has changed. -// -// In the future we will want to remove this funcion in favour of a system that -// makes sure that statics don't need to have edges to other statics as long as -// they are only referring by reference and not inspecting the other static's body. -fn create_depgraph_edges<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - alloc_id: AllocId, - seen: &mut FxHashSet, -) { - trace!("create_depgraph_edges: {:?}, {:?}", alloc_id, seen); - if seen.insert(alloc_id) { - trace!("seen: {:?}, {:?}", alloc_id, seen); - if let Some(alloc) = tcx.interpret_interner.get_alloc(alloc_id) { - trace!("get_alloc: {:?}, {:?}, {:?}", alloc_id, seen, alloc); - for (_, &reloc) in &alloc.relocations { - if let Some(did) = tcx.interpret_interner.get_corresponding_static_def_id(reloc) { - trace!("get_corresponding: {:?}, {:?}, {:?}, {:?}, {:?}", alloc_id, seen, alloc, did, reloc); - let _ = tcx.maybe_optimized_mir(did); - } - create_depgraph_edges(tcx, reloc, seen); - } - } - } -} diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index b8bfcd756cd23..7fb793f43510c 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -929,16 +929,14 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { - if gid.promoted.is_none() { - let cached = self + if self.tcx.is_static(gid.instance.def_id()).is_some() { + let alloc_id = self .tcx .interpret_interner - .get_cached(gid.instance.def_id()); - if let Some(alloc_id) = cached { - let layout = self.layout_of(ty)?; - let ptr = MemoryPointer::new(alloc_id, 0); - return Ok(Value::ByRef(ptr.into(), layout.align)) - } + .cache_static(gid.instance.def_id()); + let layout = self.layout_of(ty)?; + let ptr = MemoryPointer::new(alloc_id, 0); + return Ok(Value::ByRef(ptr.into(), layout.align)) } let cv = self.const_eval(gid)?; self.const_to_value(&cv.val, ty) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 446ef6bd32876..f71b06e4ddf3f 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1111,7 +1111,7 @@ fn collect_miri<'a, 'tcx>( alloc_id: AllocId, output: &mut Vec>, ) { - if let Some(did) = tcx.interpret_interner.get_corresponding_static_def_id(alloc_id) { + if let Some(did) = tcx.interpret_interner.get_static(alloc_id) { let instance = Instance::mono(tcx, did); if should_monomorphize_locally(tcx, &instance) { trace!("collecting static {:?}", did); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 977c7c983d6f2..6e07b8e73ef22 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -50,7 +50,7 @@ pub fn primval_to_llvm(cx: &CodegenCx, let static_ = cx .tcx .interpret_interner - .get_corresponding_static_def_id(ptr.alloc_id); + .get_static(ptr.alloc_id); let base_addr = if let Some(def_id) = static_ { assert!(cx.tcx.is_static(def_id).is_some()); consts::get_static(cx, def_id) @@ -126,18 +126,17 @@ pub fn trans_static_initializer<'a, 'tcx>( promoted: None }; let param_env = ty::ParamEnv::reveal_all(); - cx.tcx.const_eval(param_env.and(cid))?; + let static_ = cx.tcx.const_eval(param_env.and(cid))?; - let alloc_id = cx - .tcx - .interpret_interner - .get_cached(def_id) - .expect("global not cached"); + let ptr = match static_.val { + ConstVal::Value(MiriValue::ByRef(ptr, _)) => ptr, + _ => bug!("static const eval returned {:#?}", static_), + }; let alloc = cx .tcx .interpret_interner - .get_alloc(alloc_id) + .get_alloc(ptr.primval.to_ptr().expect("static has integer pointer").alloc_id) .expect("miri allocation never successfully created"); Ok(global_initializer(cx, alloc)) } From 0734f0e3f452546e529260983571567fd75ffe0f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 11 Apr 2018 10:47:52 +0200 Subject: [PATCH 03/15] Use `LazySeq` instead of `Vec` --- src/librustc_metadata/decoder.rs | 22 ++++++++++++++---- src/librustc_metadata/encoder.rs | 39 ++++++++++++++++++-------------- src/librustc_metadata/schema.rs | 2 +- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 2d0037e466cb0..155223c374957 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -59,6 +59,9 @@ pub struct DecodeContext<'a, 'tcx: 'a> { // interpreter allocation cache interpret_alloc_cache: FxHashMap, + + // Read from the LazySeq CrateRoot::inpterpret_alloc_index on demand + interpret_alloc_index: Option>, } /// Abstract over the various ways one can create metadata decoders. @@ -78,6 +81,7 @@ pub trait Metadata<'a, 'tcx>: Copy { last_filemap_index: 0, lazy_state: LazyState::NoNode, interpret_alloc_cache: FxHashMap::default(), + interpret_alloc_index: None, } } } @@ -176,6 +180,17 @@ 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 index = self.cdata().root.interpret_alloc_index; + let index: Vec = index.decode(self.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> { @@ -292,11 +307,8 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx if let Some(cached) = self.interpret_alloc_cache.get(&idx).cloned() { return Ok(cached); } - let pos = self - .cdata() - .root - .interpret_alloc_index[idx]; - self.with_position(pos as usize, |this| { + let pos = self.interpret_alloc(idx); + self.with_position(pos, |this| { interpret::specialized_decode_alloc_id( this, tcx, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 549c5bd760fb9..d9b9cd5d3002b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -265,7 +265,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { start - min_end } LazyState::Previous(last_min_end) => { - assert!(last_min_end <= position); + assert!( + last_min_end <= position, + "make sure that the calls to `lazy*` \ + are in the same order as the metadata fields", + ); position - last_min_end } }; @@ -439,21 +443,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { IsolatedEncoder::encode_wasm_custom_sections, &wasm_custom_sections); - // Encode and index the items. - i = self.position(); - let items = self.encode_info_for_items(); - let item_bytes = self.position() - i; - - i = self.position(); - let index = items.write_index(&mut self.opaque.cursor); - let index_bytes = self.position() - i; - let tcx = self.tcx; - let link_meta = self.link_meta; - let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro); - let has_default_lib_allocator = - attr::contains_name(tcx.hir.krate_attrs(), "default_lib_allocator"); - let has_global_allocator = tcx.sess.has_global_allocator.get(); // Encode the allocation index let interpret_alloc_index = { @@ -478,9 +468,24 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } n = new_n; } - interpret_alloc_index + self.lazy_seq(interpret_alloc_index) }; + // Encode and index the items. + i = self.position(); + let items = self.encode_info_for_items(); + let item_bytes = self.position() - i; + + i = self.position(); + let index = items.write_index(&mut self.opaque.cursor); + let index_bytes = self.position() - i; + + let link_meta = self.link_meta; + let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro); + let has_default_lib_allocator = + attr::contains_name(tcx.hir.krate_attrs(), "default_lib_allocator"); + let has_global_allocator = tcx.sess.has_global_allocator.get(); + let root = self.lazy(&CrateRoot { name: tcx.crate_name(LOCAL_CRATE), triple: tcx.sess.opts.target_triple.clone(), @@ -511,8 +516,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { impls, exported_symbols, wasm_custom_sections, - index, interpret_alloc_index, + index, }); let total_bytes = self.position(); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index d7a766c90c60b..075efe01cdff7 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -207,7 +207,7 @@ pub struct CrateRoot { pub impls: LazySeq, pub exported_symbols: LazySeq<(ExportedSymbol, SymbolExportLevel)>, pub wasm_custom_sections: LazySeq, - pub interpret_alloc_index: Vec, + pub interpret_alloc_index: LazySeq, pub index: LazySeq, } From 45d5b64b84c84caa45fc402f89167f743f0a25cf Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 11 Apr 2018 13:31:37 +0200 Subject: [PATCH 04/15] Encode items before encoding the list of AllocIds --- src/librustc_metadata/encoder.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index d9b9cd5d3002b..13559f6b017ca 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -445,12 +445,24 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tcx = self.tcx; + // Encode the items. + i = self.position(); + 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_alloc_ids.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; @@ -461,21 +473,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { id, ).unwrap(); } - // if we have found new ids, serialize those, too - if n == new_n { - // otherwise, abort - break; - } n = new_n; } self.lazy_seq(interpret_alloc_index) }; - // Encode and index the items. - i = self.position(); - let items = self.encode_info_for_items(); - let item_bytes = self.position() - i; - + // Index the items i = self.position(); let index = items.write_index(&mut self.opaque.cursor); let index_bytes = self.position() - i; From 84be1fdea2f8c3090ca98b4203428da28e0fd2b3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 11 Apr 2018 13:31:51 +0200 Subject: [PATCH 05/15] Reduce the number of calls to `cdata` --- src/librustc_metadata/decoder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 155223c374957..20e2ada5bd9b3 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -185,8 +185,8 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { if let Some(index) = self.interpret_alloc_index.as_mut() { return index[idx] as usize; } - let index = self.cdata().root.interpret_alloc_index; - let index: Vec = index.decode(self.cdata()).collect(); + 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 From 3d1f645d289780c723ba13a103783f6cacac4d7a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 13 Apr 2018 18:48:41 +0200 Subject: [PATCH 06/15] Get rid of redundant `HashSet` --- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc/ty/maps/on_disk_cache.rs | 31 +++++++++++++-------------- src/librustc_metadata/encoder.rs | 25 +++++++++++---------- 3 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 07768ac3a3b97..c9eed0e4a2885 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -178,7 +178,7 @@ pub fn specialized_encode_alloc_id< AllocKind::Fn.encode(encoder)?; fn_instance.encode(encoder)?; } else if let Some(did) = tcx.interpret_interner.get_static(alloc_id) { - // referring to statics doesn't need to know about their allocations, just hash the DefId + // referring to statics doesn't need to know about their allocations, just about its DefId AllocKind::Static.encode(encoder)?; did.encode(encoder)?; } else { diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 7b340ebe784ad..8cf98aedbe7fd 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -200,7 +200,6 @@ impl<'sess> OnDiskCache<'sess> { predicate_shorthands: FxHashMap(), expn_info_shorthands: FxHashMap(), interpret_allocs: FxHashMap(), - interpret_alloc_ids: FxHashSet(), interpret_allocs_inverse: Vec::new(), codemap: CachingCodemapView::new(tcx.sess.codemap()), file_to_file_index, @@ -279,7 +278,12 @@ impl<'sess> OnDiskCache<'sess> { let mut interpret_alloc_index = Vec::new(); let mut n = 0; loop { - let new_n = encoder.interpret_alloc_ids.len(); + 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()); @@ -290,11 +294,6 @@ impl<'sess> OnDiskCache<'sess> { id, )?; } - // if we have found new ids, serialize those, too - if n == new_n { - // otherwise, abort - break; - } n = new_n; } interpret_alloc_index @@ -798,7 +797,6 @@ struct CacheEncoder<'enc, 'a, 'tcx, E> expn_info_shorthands: FxHashMap, interpret_allocs: FxHashMap, interpret_allocs_inverse: Vec, - interpret_alloc_ids: FxHashSet, codemap: CachingCodemapView<'tcx>, file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>, } @@ -835,14 +833,15 @@ 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> { - let index = if self.interpret_alloc_ids.insert(*alloc_id) { - let idx = self.interpret_alloc_ids.len() - 1; - assert_eq!(idx, self.interpret_allocs_inverse.len()); - self.interpret_allocs_inverse.push(*alloc_id); - assert!(self.interpret_allocs.insert(*alloc_id, idx).is_none()); - idx - } else { - self.interpret_allocs[alloc_id] + 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) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 13559f6b017ca..a0d14e3da7325 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -29,7 +29,7 @@ use rustc::ty::{self, Ty, TyCtxt, ReprOptions, SymbolName}; use rustc::ty::codec::{self as ty_codec, TyEncoder}; use rustc::session::config::{self, CrateTypeProcMacro}; -use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc::util::nodemap::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; @@ -62,7 +62,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> { interpret_allocs: FxHashMap, interpret_allocs_inverse: Vec, - interpret_alloc_ids: FxHashSet, // This is used to speed up Span encoding. filemap_cache: Lrc, @@ -199,14 +198,15 @@ 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> { - let index = if self.interpret_alloc_ids.insert(*alloc_id) { - let idx = self.interpret_alloc_ids.len() - 1; - assert_eq!(idx, self.interpret_allocs_inverse.len()); - self.interpret_allocs_inverse.push(*alloc_id); - assert!(self.interpret_allocs.insert(*alloc_id, idx).is_none()); - idx - } else { - self.interpret_allocs[alloc_id] + 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) @@ -456,7 +456,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let mut n = 0; trace!("beginning to encode alloc ids"); loop { - let new_n = self.interpret_alloc_ids.len(); + let new_n = self.interpret_allocs_inverse.len(); // if we have found new ids, serialize those, too if n == new_n { // otherwise, abort @@ -487,7 +487,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro); let has_default_lib_allocator = attr::contains_name(tcx.hir.krate_attrs(), "default_lib_allocator"); - let has_global_allocator = tcx.sess.has_global_allocator.get(); + let has_global_allocator = *tcx.sess.has_global_allocator.get(); let root = self.lazy(&CrateRoot { name: tcx.crate_name(LOCAL_CRATE), @@ -1786,7 +1786,6 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, filemap_cache: tcx.sess.codemap().files()[0].clone(), interpret_allocs: Default::default(), interpret_allocs_inverse: Default::default(), - interpret_alloc_ids: Default::default(), }; // Encode the rustc version string in a predictable location. From a1840973d9a2de9fc517cf3ef498264e3d61afb9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 17 Apr 2018 16:12:58 +0200 Subject: [PATCH 07/15] Difference between master and beta --- src/librustc_metadata/encoder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a0d14e3da7325..a06418b543932 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -487,7 +487,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro); let has_default_lib_allocator = attr::contains_name(tcx.hir.krate_attrs(), "default_lib_allocator"); - let has_global_allocator = *tcx.sess.has_global_allocator.get(); + let has_global_allocator = tcx.sess.has_global_allocator.get(); let root = self.lazy(&CrateRoot { name: tcx.crate_name(LOCAL_CRATE), From 2b9e857d513d973deb0cfa578e462cf807475d84 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 13 Apr 2018 18:31:15 +0200 Subject: [PATCH 08/15] Sign extend constants in range patterns --- src/librustc_mir/hair/pattern/_match.rs | 18 +++++++++------- src/librustc_mir/hair/pattern/mod.rs | 17 +++++++++++---- src/librustc_mir/interpret/eval_context.rs | 14 ++----------- src/librustc_mir/interpret/mod.rs | 24 ++++++++++++++++++++++ src/test/ui/const-eval/const_signed_pat.rs | 19 +++++++++++++++++ 5 files changed, 69 insertions(+), 23 deletions(-) create mode 100644 src/test/ui/const-eval/const_signed_pat.rs diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 6f8b1f8e79940..ff7b4f9e0fd70 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -985,15 +985,17 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, Ok(true) } -fn constructor_covered_by_range(ctor: &Constructor, - from: &ConstVal, to: &ConstVal, - end: RangeEnd, - ty: Ty) - -> Result { +fn constructor_covered_by_range<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + ctor: &Constructor, + from: &ConstVal, to: &ConstVal, + end: RangeEnd, + ty: Ty<'tcx>, +) -> Result { trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); - let cmp_from = |c_from| compare_const_vals(c_from, from, ty) + let cmp_from = |c_from| compare_const_vals(tcx, c_from, from, ty) .map(|res| res != Ordering::Less); - let cmp_to = |c_to| compare_const_vals(c_to, to, ty); + let cmp_to = |c_to| compare_const_vals(tcx, c_to, to, ty); macro_rules! some_or_ok { ($e:expr) => { match $e { @@ -1105,6 +1107,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( }, _ => { match constructor_covered_by_range( + cx.tcx, constructor, &value.val, &value.val, RangeEnd::Included, value.ty, ) { @@ -1118,6 +1121,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Range { lo, hi, ref end } => { match constructor_covered_by_range( + cx.tcx, constructor, &lo.val, &hi.val, end.clone(), lo.ty, ) { Ok(true) => Some(vec![]), diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 798d635318180..02aca73c55305 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -16,7 +16,7 @@ mod check_match; pub use self::check_match::check_crate; pub(crate) use self::check_match::check_match; -use interpret::{const_val_field, const_discr}; +use interpret::{const_val_field, const_discr, self}; use rustc::middle::const_val::ConstVal; use rustc::mir::{Field, BorrowKind, Mutability}; @@ -372,7 +372,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { use std::cmp::Ordering; - match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) { + match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) { (RangeEnd::Excluded, Ordering::Less) => PatternKind::Range { lo, hi, end }, (RangeEnd::Excluded, _) => { @@ -1092,7 +1092,12 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { } } -pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { +pub fn compare_const_vals<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + a: &ConstVal, + b: &ConstVal, + ty: Ty<'tcx>, +) -> Option { use rustc_const_math::ConstFloat; trace!("compare_const_vals: {:?}, {:?}", a, b); use rustc::mir::interpret::{Value, PrimVal}; @@ -1112,7 +1117,11 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option Some((a as i128).cmp(&(b as i128))), + ty::TyInt(_) => { + let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt"); + let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt"); + Some((a as i128).cmp(&(b as i128))) + }, _ => Some(a.cmp(&b)), } }, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 7fb793f43510c..e85f594068947 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1670,21 +1670,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { - let layout = self.layout_of(ty)?; - let size = layout.size.bits(); - assert!(layout.abi.is_signed()); - // sign extend - let amt = 128 - size; - // shift the unsigned value to the left - // and back to the right as signed (essentially fills with FF on the left) - Ok((((value << amt) as i128) >> amt) as u128) + super::sign_extend(self.tcx.tcx, value, ty) } pub fn truncate(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { - let size = self.layout_of(ty)?.size.bits(); - let amt = 128 - size; - // truncate (shift left to drop out leftover values, shift right to fill with zeroes) - Ok((value << amt) >> amt) + super::truncate(self.tcx.tcx, value, ty) } } diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index ae6337d82c3e3..147db3bdc0e7a 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -31,3 +31,27 @@ pub use self::const_eval::{ pub use self::machine::Machine; pub use self::memory::{write_target_uint, write_target_int, read_target_uint}; + +use rustc::mir::interpret::{EvalResult, EvalErrorKind}; +use rustc::ty::{Ty, TyCtxt, ParamEnv}; + +pub fn sign_extend<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { + let param_env = ParamEnv::empty(); + let layout = tcx.layout_of(param_env.and(ty)).map_err(|layout| EvalErrorKind::Layout(layout))?; + let size = layout.size.bits(); + assert!(layout.abi.is_signed()); + // sign extend + let amt = 128 - size; + // shift the unsigned value to the left + // and back to the right as signed (essentially fills with FF on the left) + Ok((((value << amt) as i128) >> amt) as u128) +} + +pub fn truncate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { + let param_env = ParamEnv::empty(); + let layout = tcx.layout_of(param_env.and(ty)).map_err(|layout| EvalErrorKind::Layout(layout))?; + let size = layout.size.bits(); + let amt = 128 - size; + // truncate (shift left to drop out leftover values, shift right to fill with zeroes) + Ok((value << amt) >> amt) +} diff --git a/src/test/ui/const-eval/const_signed_pat.rs b/src/test/ui/const-eval/const_signed_pat.rs new file mode 100644 index 0000000000000..f4d3a71b0f534 --- /dev/null +++ b/src/test/ui/const-eval/const_signed_pat.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully + +fn main() { + const MIN: i8 = -5; + match 5i8 { + MIN...-1 => {}, + _ => {}, + } +} From 2cc625d25481929b0be64ec6186163b5d9957d08 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 13 Apr 2018 17:56:45 +0200 Subject: [PATCH 09/15] Don't abort const eval due to long running evals, just warn --- src/librustc/ich/impls_ty.rs | 1 - src/librustc/mir/interpret/error.rs | 3 --- src/librustc/session/mod.rs | 3 --- src/librustc/ty/structural_impls.rs | 1 - src/librustc_mir/interpret/eval_context.rs | 6 +++--- src/librustc_mir/interpret/step.rs | 13 ++++++------- 6 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 17cbfc7a2c21c..63248e036c8f4 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -533,7 +533,6 @@ for ::mir::interpret::EvalError<'gcx> { InvalidPointerMath | ReadUndefBytes | DeadLocal | - ExecutionTimeLimitReached | StackFrameLimitReached | OutOfTls | TlsOutOfBounds | diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 9e69990f22c0d..b919f4d15a840 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -65,7 +65,6 @@ pub enum EvalErrorKind<'tcx> { Intrinsic(String), OverflowingMath, InvalidChar(u128), - ExecutionTimeLimitReached, StackFrameLimitReached, OutOfTls, TlsOutOfBounds, @@ -188,8 +187,6 @@ impl<'tcx> Error for EvalError<'tcx> { "mir not found", InvalidChar(..) => "tried to interpret an invalid 32-bit value as a char", - ExecutionTimeLimitReached => - "the expression was too complex to be evaluated or resulted in an infinite loop", StackFrameLimitReached => "reached the configured maximum number of stack frames", OutOfTls => diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 77cf50a8341ed..3afddbdfaed7f 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -108,8 +108,6 @@ pub struct Session { /// The maximum number of stackframes allowed in const eval pub const_eval_stack_frame_limit: Cell, - /// The maximum number miri steps per constant - pub const_eval_step_limit: Cell, /// The metadata::creader module may inject an allocator/panic_runtime /// dependency if it didn't already find one, and this tracks what was @@ -1146,7 +1144,6 @@ pub fn build_session_( recursion_limit: Cell::new(64), type_length_limit: Cell::new(1048576), const_eval_stack_frame_limit: Cell::new(100), - const_eval_step_limit: Cell::new(1_000_000), next_node_id: Cell::new(NodeId::new(1)), injected_allocator: Cell::new(None), allocator_kind: Cell::new(None), diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 8cf662ccaea92..7b4b7082bb6ce 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -509,7 +509,6 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { Intrinsic(ref s) => Intrinsic(s.clone()), OverflowingMath => OverflowingMath, InvalidChar(c) => InvalidChar(c), - ExecutionTimeLimitReached => ExecutionTimeLimitReached, StackFrameLimitReached => StackFrameLimitReached, OutOfTls => OutOfTls, TlsOutOfBounds => TlsOutOfBounds, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e85f594068947..415bef249a95a 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -45,7 +45,7 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// The maximum number of terminators that may be evaluated. /// This prevents infinite loops and huge computations from freezing up const eval. /// Remove once halting problem is solved. - pub(crate) steps_remaining: usize, + pub(crate) terminators_remaining: usize, } /// A stack frame. @@ -195,7 +195,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M memory: Memory::new(tcx, memory_data), stack: Vec::new(), stack_limit: tcx.sess.const_eval_stack_frame_limit.get(), - steps_remaining: tcx.sess.const_eval_step_limit.get(), + terminators_remaining: 1_000_000, } } @@ -538,7 +538,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } Aggregate(ref kind, ref operands) => { - self.inc_step_counter_and_check_limit(operands.len())?; + self.inc_step_counter_and_check_limit(operands.len()); let (dest, active_field_index) = match **kind { mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => { diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index a22572ec687c3..f891d2b8ccb1d 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -8,12 +8,11 @@ use rustc::mir::interpret::EvalResult; use super::{EvalContext, Machine}; impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { - pub fn inc_step_counter_and_check_limit(&mut self, n: usize) -> EvalResult<'tcx> { - self.steps_remaining = self.steps_remaining.saturating_sub(n); - if self.steps_remaining > 0 { - Ok(()) - } else { - err!(ExecutionTimeLimitReached) + pub fn inc_step_counter_and_check_limit(&mut self, n: usize) { + self.terminators_remaining = self.terminators_remaining.saturating_sub(n); + if self.terminators_remaining == 0 { + self.tcx.sess.span_warn(self.frame().span, "Constant evaluating a complex constant, this might take some time"); + self.terminators_remaining = 1_000_000; } } @@ -36,7 +35,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { return Ok(true); } - self.inc_step_counter_and_check_limit(1)?; + self.inc_step_counter_and_check_limit(1); let terminator = basic_block.terminator(); assert_eq!(old_frames, self.cur_frame()); From 2548259b0dd064f722df2e77544348e2769d65e2 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 15 Apr 2018 13:28:15 +0200 Subject: [PATCH 10/15] Add a tracking issue for making the warning a lint --- src/librustc_mir/interpret/step.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index f891d2b8ccb1d..554d87a04e2f8 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -11,6 +11,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub fn inc_step_counter_and_check_limit(&mut self, n: usize) { self.terminators_remaining = self.terminators_remaining.saturating_sub(n); if self.terminators_remaining == 0 { + // FIXME(#49980): make this warning a lint self.tcx.sess.span_warn(self.frame().span, "Constant evaluating a complex constant, this might take some time"); self.terminators_remaining = 1_000_000; } From 7e2aadaebfb3d1cae91a470f515afe7abf30f122 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 11 Apr 2018 14:56:59 +0200 Subject: [PATCH 11/15] Don't inject clippy into rls on stable/beta --- src/bootstrap/tool.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 2bb46cc5171d6..c106a66f06735 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -564,7 +564,8 @@ tool_extended!((self, builder), target: self.target, extra_features: Vec::new(), }); - if clippy.is_some() { + let channel = &builder.config.channel; + if clippy.is_some() && channel != "stable" && channel != "beta" { self.extra_features.push("clippy".to_owned()); } builder.ensure(native::Openssl { From d7b7bdadf5a6fdffbb1aa8e56adf271c76950550 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 12 Apr 2018 14:51:10 +0200 Subject: [PATCH 12/15] Add #[no_debug] to trans_fn_attrs() query. --- src/librustc/hir/mod.rs | 1 + src/librustc_typeck/collect.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index be8cceb611896..a65a461a228ad 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2280,6 +2280,7 @@ bitflags! { const NAKED = 0b0001_0000; const NO_MANGLE = 0b0010_0000; const RUSTC_STD_INTERNAL_SYMBOL = 0b0100_0000; + const NO_DEBUG = 0b1000_0000; } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 59156bf0dfeaa..b2bc5114034d5 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1785,6 +1785,8 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt trans_fn_attrs.flags |= TransFnAttrFlags::NO_MANGLE; } else if attr.check_name("rustc_std_internal_symbol") { trans_fn_attrs.flags |= TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; + } else if attr.check_name("no_debug") { + trans_fn_attrs.flags |= TransFnAttrFlags::NO_DEBUG; } else if attr.check_name("inline") { trans_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { if attr.path != "inline" { From 0ad34dc4bc30312176ea836e137b057f3a2cc793 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 12 Apr 2018 14:52:09 +0200 Subject: [PATCH 13/15] Support #[no_debug] for global variables. --- src/librustc_trans/debuginfo/metadata.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index f3d95cf794bab..eb550d7a605c5 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -23,6 +23,7 @@ use llvm::{self, ValueRef}; use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType, DILexicalBlock, DIFlags}; +use rustc::hir::TransFnAttrFlags; use rustc::hir::def::CtorKind; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::ty::fold::TypeVisitor; @@ -41,7 +42,7 @@ use std::ffi::CString; use std::fmt::Write; use std::ptr; use std::path::{Path, PathBuf}; -use syntax::{ast, attr}; +use syntax::ast; use syntax::symbol::{Interner, InternedString, Symbol}; use syntax_pos::{self, Span, FileName}; @@ -1644,11 +1645,17 @@ pub fn create_global_var_metadata(cx: &CodegenCx, } let tcx = cx.tcx; - let no_mangle = attr::contains_name(&tcx.get_attrs(def_id), "no_mangle"); + let attrs = tcx.trans_fn_attrs(def_id); + + if attrs.flags.contains(TransFnAttrFlags::NO_DEBUG) { + return; + } + + let no_mangle = attrs.flags.contains(TransFnAttrFlags::NO_MANGLE); // We may want to remove the namespace scope if we're in an extern block, see: // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952 let var_scope = get_namespace_for_item(cx, def_id); - let span = cx.tcx.def_span(def_id); + let span = tcx.def_span(def_id); let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP { let loc = span_start(cx, span); From a95f876641a6c803ed16d802df69d819d2880a9c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 12 Apr 2018 14:53:50 +0200 Subject: [PATCH 14/15] Use #[no_debug] to work around LLVM problem with rustc_driver::get_trans::LOAD. --- src/librustc_driver/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b9bcbccb30ef3..75416e319cd19 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -24,6 +24,7 @@ #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(set_stdio)] +#![feature(no_debug)] extern crate arena; extern crate getopts; @@ -230,6 +231,9 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box { pub fn get_trans(sess: &Session) -> Box { static INIT: Once = ONCE_INIT; + + #[allow(deprecated)] + #[no_debug] static mut LOAD: fn() -> Box = || unreachable!(); INIT.call_once(|| { From 775d70bb6e77d76d75ec8fdd96cd97148d441c45 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 12 Apr 2018 14:52:43 +0200 Subject: [PATCH 15/15] Clean up attribute handling in create_function_debug_context(). --- src/librustc_trans/debuginfo/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 7664c88679e0e..762e705e7ed32 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -23,6 +23,7 @@ use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; use llvm; use llvm::{ModuleRef, ContextRef, ValueRef}; use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags}; +use rustc::hir::TransFnAttrFlags; use rustc::hir::def_id::{DefId, CrateNum}; use rustc::ty::subst::Substs; @@ -30,7 +31,7 @@ use abi::Abi; use common::CodegenCx; use builder::Builder; use monomorphize::Instance; -use rustc::ty::{self, ParamEnv, Ty}; +use rustc::ty::{self, ParamEnv, Ty, InstanceDef}; use rustc::mir; use rustc::session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; @@ -210,13 +211,12 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, return FunctionDebugContext::DebugInfoDisabled; } - for attr in instance.def.attrs(cx.tcx).iter() { - if attr.check_name("no_debug") { + if let InstanceDef::Item(def_id) = instance.def { + if cx.tcx.trans_fn_attrs(def_id).flags.contains(TransFnAttrFlags::NO_DEBUG) { return FunctionDebugContext::FunctionWithoutDebugInfo; } } - let containing_scope = get_containing_scope(cx, instance); let span = mir.span; // This can be the case for functions inlined from another crate @@ -226,6 +226,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } let def_id = instance.def_id(); + let containing_scope = get_containing_scope(cx, instance); let loc = span_start(cx, span); let file_metadata = file_metadata(cx, &loc.file.name, def_id.krate);