diff --git a/src/Cargo.lock b/src/Cargo.lock index daa8d0dc84cea..e03d9454d062f 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -66,6 +66,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arena" version = "0.0.0" +dependencies = [ + "rustc_data_structures 0.0.0", +] [[package]] name = "arrayvec" diff --git a/src/libarena/Cargo.toml b/src/libarena/Cargo.toml index b53c0a2f48bf7..e2af67dd92861 100644 --- a/src/libarena/Cargo.toml +++ b/src/libarena/Cargo.toml @@ -7,3 +7,6 @@ version = "0.0.0" name = "arena" path = "lib.rs" crate-type = ["dylib"] + +[dependencies] +rustc_data_structures = { path = "../librustc_data_structures" } \ No newline at end of file diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index b319f333342c1..c79e0e14e3d8b 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -32,6 +32,9 @@ #![allow(deprecated)] extern crate alloc; +extern crate rustc_data_structures; + +use rustc_data_structures::sync::MTLock; use std::cell::{Cell, RefCell}; use std::cmp; @@ -290,6 +293,8 @@ pub struct DroplessArena { chunks: RefCell>>, } +unsafe impl Send for DroplessArena {} + impl DroplessArena { pub fn new() -> DroplessArena { DroplessArena { @@ -410,6 +415,72 @@ impl DroplessArena { } } +pub struct SyncTypedArena { + lock: MTLock>, +} + +impl SyncTypedArena { + #[inline(always)] + pub fn new() -> SyncTypedArena { + SyncTypedArena { + lock: MTLock::new(TypedArena::new()) + } + } + + #[inline(always)] + pub fn alloc(&self, object: T) -> &mut T { + // Extend the lifetime of the result since it's limited to the lock guard + unsafe { &mut *(self.lock.lock().alloc(object) as *mut T) } + } + + #[inline(always)] + pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] + where + T: Copy, + { + // Extend the lifetime of the result since it's limited to the lock guard + unsafe { &mut *(self.lock.lock().alloc_slice(slice) as *mut [T]) } + } + + #[inline(always)] + pub fn clear(&mut self) { + self.lock.get_mut().clear(); + } +} + +pub struct SyncDroplessArena { + lock: MTLock, +} + +impl SyncDroplessArena { + #[inline(always)] + pub fn new() -> SyncDroplessArena { + SyncDroplessArena { + lock: MTLock::new(DroplessArena::new()) + } + } + + #[inline(always)] + pub fn in_arena(&self, ptr: *const T) -> bool { + self.lock.lock().in_arena(ptr) + } + + #[inline(always)] + pub fn alloc(&self, object: T) -> &mut T { + // Extend the lifetime of the result since it's limited to the lock guard + unsafe { &mut *(self.lock.lock().alloc(object) as *mut T) } + } + + #[inline(always)] + pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] + where + T: Copy, + { + // Extend the lifetime of the result since it's limited to the lock guard + unsafe { &mut *(self.lock.lock().alloc_slice(slice) as *mut [T]) } + } +} + #[cfg(test)] mod tests { extern crate test; diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 1e348e3a31ce2..b88185c3154a9 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -32,7 +32,7 @@ use hir::print::Nested; use hir::svh::Svh; use util::nodemap::{DefIdMap, FxHashMap}; -use arena::TypedArena; +use arena::SyncTypedArena; use std::io; use ty::TyCtxt; @@ -219,7 +219,7 @@ impl<'hir> MapEntry<'hir> { pub struct Forest { krate: Crate, pub dep_graph: DepGraph, - inlined_bodies: TypedArena + inlined_bodies: SyncTypedArena } impl Forest { @@ -227,7 +227,7 @@ impl Forest { Forest { krate, dep_graph: dep_graph.clone(), - inlined_bodies: TypedArena::new() + inlined_bodies: SyncTypedArena::new() } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 84bf9cc84e737..40cc43c3ca670 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -37,7 +37,7 @@ use errors::DiagnosticBuilder; use syntax_pos::{self, Span}; use syntax_pos::symbol::InternedString; use util::nodemap::FxHashMap; -use arena::DroplessArena; +use arena::SyncDroplessArena; use self::combine::CombineFields; use self::higher_ranked::HrMatchResult; @@ -407,7 +407,7 @@ impl fmt::Display for FixupError { /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>). pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { global_tcx: TyCtxt<'a, 'gcx, 'gcx>, - arena: DroplessArena, + arena: SyncDroplessArena, fresh_tables: Option>>, } @@ -415,7 +415,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { pub fn infer_ctxt(self) -> InferCtxtBuilder<'a, 'gcx, 'tcx> { InferCtxtBuilder { global_tcx: self, - arena: DroplessArena::new(), + arena: SyncDroplessArena::new(), fresh_tables: None, } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 9f8cc2f86992f..d5849ea22b1ef 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -27,6 +27,7 @@ use self::TargetLint::*; use std::slice; +use rustc_data_structures::sync::{RwLock, ReadGuard}; use lint::{EarlyLintPassObject, LateLintPassObject}; use lint::{Level, Lint, LintId, LintPass, LintBuffer}; use lint::builtin::BuiltinLintDiagnostics; @@ -39,7 +40,6 @@ use ty::layout::{LayoutError, LayoutOf, TyLayout}; use util::nodemap::FxHashMap; use std::default::Default as StdDefault; -use std::cell::{Ref, RefCell}; use syntax::ast; use syntax::edition; use syntax_pos::{MultiSpan, Span}; @@ -78,7 +78,7 @@ pub struct LintStore { pub struct LintSession<'a, PassObject> { /// Reference to the store of registered lints. - lints: Ref<'a, LintStore>, + lints: ReadGuard<'a, LintStore>, /// Trait objects for each lint pass. passes: Option>, @@ -336,7 +336,7 @@ impl<'a, PassObject: LintPassObject> LintSession<'a, PassObject> { /// Creates a new `LintSession`, by moving out the `LintStore`'s initial /// lint levels and pass objects. These can be restored using the `restore` /// method. - fn new(store: &'a RefCell) -> LintSession<'a, PassObject> { + fn new(store: &'a RwLock) -> LintSession<'a, PassObject> { let mut s = store.borrow_mut(); let passes = PassObject::take_passes(&mut *s); drop(s); @@ -347,7 +347,7 @@ impl<'a, PassObject: LintPassObject> LintSession<'a, PassObject> { } /// Restores the levels back to the original lint store. - fn restore(self, store: &RefCell) { + fn restore(self, store: &RwLock) { drop(self.lints); let mut s = store.borrow_mut(); PassObject::restore_passes(&mut *s, self.passes); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 32de006459d32..696bd736594d4 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -26,7 +26,7 @@ use util::nodemap::{FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; use util::common::ProfileQueriesMsg; -use rustc_data_structures::sync::{Lrc, Lock, LockCell, OneThread, Once}; +use rustc_data_structures::sync::{Lrc, Lock, LockCell, OneThread, Once, RwLock}; use syntax::ast::NodeId; use errors::{self, DiagnosticBuilder, DiagnosticId}; @@ -83,8 +83,8 @@ pub struct Session { // FIXME: lint_store and buffered_lints are not thread-safe, // but are only used in a single thread - pub lint_store: OneThread>, - pub buffered_lints: OneThread>>, + pub lint_store: RwLock, + pub buffered_lints: Lock>, /// Set of (DiagnosticId, Option, message) tuples tracking /// (sub)diagnostics that have been set once, but should not be set again, @@ -1089,8 +1089,8 @@ pub fn build_session_( default_sysroot, local_crate_source_file, working_dir, - lint_store: OneThread::new(RefCell::new(lint::LintStore::new())), - buffered_lints: OneThread::new(RefCell::new(Some(lint::LintBuffer::new()))), + lint_store: RwLock::new(lint::LintStore::new()), + buffered_lints: Lock::new(Some(lint::LintBuffer::new())), one_time_diagnostics: RefCell::new(FxHashSet()), plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())), plugin_attributes: OneThread::new(RefCell::new(Vec::new())), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ed3332f32d02f..4c7d8d7f44e6a 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -57,12 +57,11 @@ use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableHasher, StableHasherResult, StableVec}; -use arena::{TypedArena, DroplessArena}; +use arena::{TypedArena, SyncDroplessArena}; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::sync::{Lrc, Lock}; use std::any::Any; use std::borrow::Borrow; -use std::cell::Cell; use std::cmp::Ordering; use std::collections::hash_map::{self, Entry}; use std::hash::{Hash, Hasher}; @@ -83,14 +82,14 @@ use hir; pub struct AllArenas<'tcx> { pub global: GlobalArenas<'tcx>, - pub interner: DroplessArena, + pub interner: SyncDroplessArena, } impl<'tcx> AllArenas<'tcx> { pub fn new() -> Self { AllArenas { global: GlobalArenas::new(), - interner: DroplessArena::new(), + interner: SyncDroplessArena::new(), } } } @@ -130,7 +129,7 @@ type InternedSet<'tcx, T> = Lock>>; pub struct CtxtInterners<'tcx> { /// The arena that types, regions, etc are allocated from - arena: &'tcx DroplessArena, + arena: &'tcx SyncDroplessArena, /// Specifically use a speedy hash algorithm for these hash sets, /// they're accessed quite often. @@ -147,7 +146,7 @@ pub struct CtxtInterners<'tcx> { } impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { - fn new(arena: &'tcx DroplessArena) -> CtxtInterners<'tcx> { + fn new(arena: &'tcx SyncDroplessArena) -> CtxtInterners<'tcx> { CtxtInterners { arena, type_: Default::default(), @@ -174,10 +173,10 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { return ty; } let global_interner = global_interners.map(|interners| { - interners.type_.borrow_mut() + (interners.type_.borrow_mut(), &interners.arena) }); - if let Some(ref interner) = global_interner { - if let Some(&Interned(ty)) = interner.get(&st) { + if let Some((ref type_, _)) = global_interner { + if let Some(&Interned(ty)) = type_.get(&st) { return ty; } } @@ -193,18 +192,18 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { // determine that all contents are in the global tcx. // See comments on Lift for why we can't use that. if !flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) { - if let Some(interner) = global_interners { + if let Some((mut type_, arena)) = global_interner { let ty_struct: TyS<'gcx> = unsafe { mem::transmute(ty_struct) }; - let ty: Ty<'gcx> = interner.arena.alloc(ty_struct); - global_interner.unwrap().insert(Interned(ty)); + let ty: Ty<'gcx> = arena.alloc(ty_struct); + type_.insert(Interned(ty)); return ty; } } else { // Make sure we don't end up with inference // types/regions in the global tcx. - if global_interners.is_none() { + if global_interner.is_none() { drop(interner); bug!("Attempted to intern `{:?}` which contains \ inference types/regions in the global type context", @@ -915,9 +914,6 @@ pub struct GlobalCtxt<'tcx> { /// Data layout specification for the current target. pub data_layout: TargetDataLayout, - /// Used to prevent layout from recursing too deeply. - pub layout_depth: Cell, - stability_interner: Lock>, pub interpret_interner: InterpretInterner<'tcx>, @@ -1292,7 +1288,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { crate_name: Symbol::intern(crate_name), data_layout, layout_interner: Lock::new(FxHashSet()), - layout_depth: Cell::new(0), stability_interner: Lock::new(FxHashSet()), interpret_interner: Default::default(), tx_to_llvm_workers: Lock::new(tx), @@ -1559,7 +1554,7 @@ impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> { /// Call the closure with a local `TyCtxt` using the given arena. pub fn enter_local( &self, - arena: &'tcx DroplessArena, + arena: &'tcx SyncDroplessArena, f: F ) -> R where @@ -1574,6 +1569,7 @@ impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> { let new_icx = ty::tls::ImplicitCtxt { tcx, query: icx.query.clone(), + layout_depth: icx.layout_depth, }; ty::tls::enter_context(&new_icx, |new_icx| { f(new_icx.tcx) @@ -1768,6 +1764,9 @@ pub mod tls { /// The current query job, if any. This is updated by start_job in /// ty::maps::plumbing when executing a query pub query: Option>>, + + /// Used to prevent layout from recursing too deeply. + pub layout_depth: usize, } // A thread local value which stores a pointer to the current ImplicitCtxt @@ -1853,6 +1852,7 @@ pub mod tls { let icx = ImplicitCtxt { tcx, query: None, + layout_depth: 0, }; enter_context(&icx, |_| { f(tcx) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 35ada4a7227e7..6bd833568d4f3 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -896,21 +896,26 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> { - let (param_env, ty) = query.into_parts(); + ty::tls::with_related_context(tcx, move |icx| { + let rec_limit = *tcx.sess.recursion_limit.get(); + let (param_env, ty) = query.into_parts(); - let rec_limit = *tcx.sess.recursion_limit.get(); - let depth = tcx.layout_depth.get(); - if depth > rec_limit { - tcx.sess.fatal( - &format!("overflow representing the type `{}`", ty)); - } + if icx.layout_depth > rec_limit { + tcx.sess.fatal( + &format!("overflow representing the type `{}`", ty)); + } - tcx.layout_depth.set(depth+1); - let cx = LayoutCx { tcx, param_env }; - let layout = cx.layout_raw_uncached(ty); - tcx.layout_depth.set(depth); + // Update the ImplicitCtxt to increase the layout_depth + let icx = ty::tls::ImplicitCtxt { + layout_depth: icx.layout_depth + 1, + ..icx.clone() + }; - layout + ty::tls::enter_context(&icx, |_| { + let cx = LayoutCx { tcx, param_env }; + cx.layout_raw_uncached(ty) + }) + }) } pub fn provide(providers: &mut ty::maps::Providers) { diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index d60206ffd327c..f88e33c708e36 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -33,6 +33,7 @@ use ty; use ty::maps::job::QueryResult; use ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; use ty::context::TyCtxt; +use util::common::time; const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; @@ -214,7 +215,7 @@ impl<'sess> OnDiskCache<'sess> { // Encode query results let mut query_result_index = EncodedQueryResultIndex::new(); - { + time(tcx.sess, "encode query results", || { use ty::maps::queries::*; let enc = &mut encoder; let qri = &mut query_result_index; @@ -258,7 +259,9 @@ impl<'sess> OnDiskCache<'sess> { } } } - } + + Ok(()) + })?; // Encode diagnostics let diagnostics_index = { @@ -1125,6 +1128,11 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, E: 'enc + TyEncoder, Q::Value: Encodable, { + let desc = &format!("encode_query_results for {}", + unsafe { ::std::intrinsics::type_name::() }); + + time(tcx.sess, desc, || { + for (key, entry) in Q::get_cache_internal(tcx).map.iter() { if Q::cache_on_disk(key.clone()) { let entry = match *entry { @@ -1143,4 +1151,5 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } Ok(()) + }) } diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index efe7a56d80097..185db623c6f16 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -522,6 +522,7 @@ macro_rules! define_maps { let icx = ty::tls::ImplicitCtxt { tcx, query: Some(job.clone()), + layout_depth: icx.layout_depth, }; // Use the ImplicitCtxt while we execute the query diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index fe89be11764e8..a0eed9e2f8ce8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -793,9 +793,13 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); let err_count = ecx.parse_sess.span_diagnostic.err_count(); - let krate = ecx.monotonic_expander().expand_crate(krate); + let krate = time(sess, "expand crate", || { + ecx.monotonic_expander().expand_crate(krate) + }); - ecx.check_unused_macros(); + time(sess, "check unused macros", || { + ecx.check_unused_macros(); + }); let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect(); diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index a5bc1106ba0b0..e524fcecf9094 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -43,7 +43,11 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { time(sess, "persist dep-graph", || { save_in(sess, dep_graph_path(sess), - |e| encode_dep_graph(tcx, e)); + |e| { + time(sess, "encode dep-graph", || { + encode_dep_graph(tcx, e) + }) + }); }); } @@ -145,7 +149,9 @@ fn encode_dep_graph(tcx: TyCtxt, tcx.sess.opts.dep_tracking_hash().encode(encoder)?; // Encode the graph data. - let serialized_graph = tcx.dep_graph.serialize(); + let serialized_graph = time(tcx.sess, "getting serialized graph", || { + tcx.dep_graph.serialize() + }); if tcx.sess.opts.debugging_opts.incremental_info { #[derive(Clone)] @@ -221,7 +227,9 @@ fn encode_dep_graph(tcx: TyCtxt, println!("[incremental]"); } - serialized_graph.encode(encoder)?; + time(tcx.sess, "encoding serialized graph", || { + serialized_graph.encode(encoder) + })?; Ok(()) } @@ -245,5 +253,7 @@ fn encode_work_products(dep_graph: &DepGraph, fn encode_query_cache(tcx: TyCtxt, encoder: &mut Encoder) -> io::Result<()> { - tcx.serialize_query_result_cache(encoder) + time(tcx.sess, "serialize query result cache", || { + tcx.serialize_query_result_cache(encoder) + }) }