diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 74f49e141c64..b29632b1a867 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -36,6 +36,7 @@ use rustc::session::config::nightly_options; use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; +use rustc::ty::TyCtxt; use rustc::hir::def_id::{LocalCrate, LOCAL_CRATE}; use rustc::util::common::{time, ErrorReported, install_panic_hook}; use rustc_metadata::locator; @@ -103,11 +104,19 @@ pub trait Callbacks { /// Called before creating the compiler instance fn config(&mut self, _config: &mut interface::Config) {} /// Called after parsing and returns true to continue execution - fn after_parsing(&mut self, _compiler: &interface::Compiler) -> bool { + fn after_parsing<'tcx>( + &mut self, + _compiler: &interface::Compiler, + _tcx: TyCtxt<'_, 'tcx, 'tcx>, + ) -> bool { true } /// Called after analysis and returns true to continue execution - fn after_analysis(&mut self, _compiler: &interface::Compiler) -> bool { + fn after_analysis<'tcx>( + &mut self, + _compiler: &interface::Compiler, + _tcx: TyCtxt<'_, 'tcx, 'tcx>, + ) -> bool { true } } @@ -229,7 +238,8 @@ pub fn run_compiler( let pretty_info = parse_pretty(&mut config.opts, &matches); interface::run_compiler(config, |compiler| { - let sess = compiler.session(); + let sess = compiler.session().clone(); + let sess = &*sess; let should_stop = RustcDefaultCalls::print_crate_info( &**compiler.codegen_backend(), sess, @@ -247,9 +257,9 @@ pub fn run_compiler( return sess.compile_status(); } - if let Some((ppm, opt_uii)) = pretty_info { - if ppm.needs_ast_map(&opt_uii) { - compiler.enter(|tcx| { + let link = compiler.enter(|compiler, tcx| { + if let Some((ppm, opt_uii)) = pretty_info { + if ppm.needs_ast_map(&opt_uii) { let expansion_result = tcx.expand_macros(LocalCrate)?; pretty::print_after_hir_lowering( tcx, @@ -259,11 +269,8 @@ pub fn run_compiler( opt_uii.clone(), compiler.output_file().as_ref().map(|p| &**p), ); - Ok(()) - })?; - return sess.compile_status(); - } else { - compiler.enter(|tcx| { + return sess.compile_status().map(|_| None); + } else { let krate = tcx.parse(LocalCrate)?; let krate = krate.borrow(); pretty::print_after_parsing( @@ -273,57 +280,48 @@ pub fn run_compiler( ppm, compiler.output_file().as_ref().map(|p| &**p), ); - Ok(()) - })?; - return sess.compile_status(); + return sess.compile_status().map(|_| None); + } } - } - compiler.enter(|tcx| tcx.parse(LocalCrate))?; + tcx.parse(LocalCrate)?; - if !callbacks.after_parsing(compiler) { - return sess.compile_status(); - } + if !callbacks.after_parsing(compiler, tcx) { + return sess.compile_status().map(|_| None); + } - if sess.opts.debugging_opts.parse_only || - sess.opts.debugging_opts.show_span.is_some() || - sess.opts.debugging_opts.ast_json_noexpand { - return sess.compile_status(); - } + if sess.opts.debugging_opts.parse_only || + sess.opts.debugging_opts.show_span.is_some() || + sess.opts.debugging_opts.ast_json_noexpand { + return sess.compile_status().map(|_| None); + } - compiler.enter(|tcx| tcx.register_plugins(LocalCrate))?; + tcx.register_plugins(LocalCrate)?; - // Lint plugins are registered; now we can process command line flags. - if sess.opts.describe_lints { - describe_lints(&sess, &sess.lint_store.borrow(), true); - return sess.compile_status(); - } + // Lint plugins are registered; now we can process command line flags. + if sess.opts.describe_lints { + describe_lints(&sess, &sess.lint_store.borrow(), true); + return sess.compile_status().map(|_| None); + } - compiler.enter(|tcx| { tcx.prepare_outputs(LocalCrate)?; - Ok(()) - })?; - if sess.opts.output_types.contains_key(&OutputType::DepInfo) - && sess.opts.output_types.len() == 1 - { - return sess.compile_status(); - } + if sess.opts.output_types.contains_key(&OutputType::DepInfo) + && sess.opts.output_types.len() == 1 + { + return sess.compile_status().map(|_| None); + } - compiler.enter(|tcx| { tcx.lower_ast_to_hir(LocalCrate)?; - Ok(()) - })?; - if sess.opts.debugging_opts.no_analysis || - sess.opts.debugging_opts.ast_json { - return sess.compile_status(); - } + if sess.opts.debugging_opts.no_analysis || + sess.opts.debugging_opts.ast_json { + return sess.compile_status().map(|_| None); + } - if sess.opts.debugging_opts.save_analysis { - compiler.enter(|tcx| { + if sess.opts.debugging_opts.save_analysis { let expansion_result = tcx.expand_macros(LocalCrate)?; - let result = tcx.analysis(LOCAL_CRATE); + tcx.analysis(LOCAL_CRATE).ok(); let crate_name = &tcx.crate_name(LOCAL_CRATE).as_str(); time(sess, "save analysis", || { @@ -336,41 +334,36 @@ pub fn run_compiler( DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), crate_name) ) }); - - result // AST will be dropped *after* the `after_analysis` callback // (needed by the RLS) - })?; - } else { - compiler.enter(|tcx| { + } else { // Drop AST after lowering HIR to free memory mem::drop(tcx.expand_macros(LocalCrate).unwrap().ast_crate.steal()); - }); - } + } - compiler.enter(|tcx| tcx.analysis(LOCAL_CRATE))?; + tcx.analysis(LOCAL_CRATE)?; - if !callbacks.after_analysis(compiler) { - return sess.compile_status(); - } + if !callbacks.after_analysis(compiler, tcx) { + return sess.compile_status().map(|_| None); + } - if sess.opts.debugging_opts.save_analysis { - compiler.enter(|tcx| { - // Drop AST after lowering HIR to free memory + if sess.opts.debugging_opts.save_analysis { + // Drop AST after running `after_analysis` callback to free memory mem::drop(tcx.expand_macros(LocalCrate).unwrap().ast_crate.steal()); - }); - } + } - compiler.ongoing_codegen()?; + compiler.linker(tcx).map(|linker| Some(linker)) + })?; - // Drop GlobalCtxt after starting codegen to free memory - mem::drop(compiler.global_ctxt()?.take()); if sess.opts.debugging_opts.print_type_sizes { sess.code_stats.borrow().print_type_sizes(); } - compiler.link()?; + // Run linker outside `enter` so GlobalCtxt is freed + if let Some(linker) = link { + linker.link()?; + } if sess.opts.debugging_opts.perf_stats { sess.print_perf_stats(); diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index 0a16a7358b06..5bb07b284780 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -1,22 +1,25 @@ -use crate::queries::Queries; use crate::util; use crate::profile; +use crate::passes; pub use crate::passes::BoxedResolver; use rustc::lint; -use rustc::session::config::{self, Input, InputsAndOutputs}; +use rustc::session::config::{self, Input, InputsAndOutputs, OutputType}; +//use rustc::session::config::{Input, OutputFilenames, }; +use rustc::hir::def_id::{LocalCrate, LOCAL_CRATE}; use rustc::session::{DiagnosticOutput, Session}; use rustc::util::common::ErrorReported; -use rustc::ty::TyCtxt; +use rustc::ty::{self, TyCtxt}; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_data_structures::OnDrop; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{Lrc, OneThread}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_metadata::cstore::CStore; use std::io::Write; use std::path::PathBuf; use std::result; use std::sync::{Arc, Mutex}; +use std::mem; use syntax; use syntax::source_map::{FileLoader, SourceMap}; @@ -30,7 +33,6 @@ pub struct Compiler { codegen_backend: Arc, source_map: Lrc, pub(crate) io: InputsAndOutputs, - pub(crate) queries: Queries, pub(crate) cstore: Lrc, pub(crate) crate_name: Option, } @@ -57,11 +59,61 @@ impl Compiler { pub fn output_file(&self) -> &Option { &self.io.output_file } - pub fn enter(&self, f: F) -> R + pub fn enter(self, f: F) -> R where - F: for<'tcx> FnOnce(TyCtxt<'tcx, 'tcx, 'tcx>) -> R + F: for<'tcx> FnOnce(&Compiler, TyCtxt<'tcx, 'tcx, 'tcx>) -> R { - self.global_ctxt().unwrap().peek_mut().enter(f) + passes::enter_global_ctxt(&self, f) + } + pub fn linker(&self, tcx: TyCtxt<'_, '_, '_>) -> Result { + tcx.ongoing_codegen(LOCAL_CRATE).map(|ongoing_codegen| { + Linker { + sess: self.sess.clone(), + ongoing_codegen, + codegen_backend: self.codegen_backend.clone(), + } + }) + } + pub fn compile(self) -> Result<()> { + let link = self.enter(|compiler, tcx| { + tcx.prepare_outputs(LocalCrate)?; + + if tcx.sess.opts.output_types.contains_key(&OutputType::DepInfo) + && tcx.sess.opts.output_types.len() == 1 + { + return Ok(None) + } + + tcx.lower_ast_to_hir(LocalCrate)?; + // Drop AST after lowering HIR to free memory + mem::drop(tcx.expand_macros(LocalCrate).unwrap().ast_crate.steal()); + + compiler.linker(tcx).map(|linker| Some(linker)) + })?; + + // Run linker outside `enter` so GlobalCtxt is freed + if let Some(linker) = link { + linker.link() + } else { + Ok(()) + } + } +} + +pub struct Linker { + sess: Lrc, + ongoing_codegen: Lrc, + codegen_backend: Arc, +} + +impl Linker { + pub fn link(self) -> Result<()> { + self.codegen_backend.join_codegen_and_link( + OneThread::into_inner(self.ongoing_codegen.codegen_object.steal()), + &self.sess, + &self.ongoing_codegen.dep_graph, + &self.ongoing_codegen.outputs, + ).map_err(|_| ErrorReported) } } @@ -89,7 +141,7 @@ pub struct Config { pub fn run_compiler_in_existing_thread_pool(config: Config, f: F) -> R where - F: FnOnce(&Compiler) -> R, + F: FnOnce(Compiler) -> R, { let (sess, codegen_backend, source_map) = util::create_session( config.opts, @@ -103,7 +155,7 @@ where let cstore = Lrc::new(CStore::new(codegen_backend.metadata_loader())); let compiler = Compiler { - sess, + sess: sess.clone(), codegen_backend, source_map, cstore, @@ -113,24 +165,23 @@ where output_dir: config.output_dir, output_file: config.output_file, }, - queries: Default::default(), crate_name: config.crate_name, }; - let _sess_abort_error = OnDrop(|| compiler.sess.diagnostic().print_error_count()); + let _sess_abort_error = OnDrop(|| sess.diagnostic().print_error_count()); - if compiler.sess.profile_queries() { - profile::begin(&compiler.sess); + if sess.profile_queries() { + profile::begin(&sess); } - let r = f(&compiler); + let r = f(compiler); - if compiler.sess.profile_queries() { - profile::dump(&compiler.sess, "profile_queries".to_string()) + if sess.profile_queries() { + profile::dump(&sess, "profile_queries".to_string()) } - if compiler.sess.opts.debugging_opts.self_profile { - compiler.sess.profiler(|p| p.dump_raw_events(&compiler.sess.opts)); + if sess.opts.debugging_opts.self_profile { + sess.profiler(|p| p.dump_raw_events(&sess.opts)); } r @@ -138,7 +189,7 @@ where pub fn run_compiler(mut config: Config, f: F) -> R where - F: FnOnce(&Compiler) -> R + Send, + F: FnOnce(Compiler) -> R + Send, R: Send, { let stderr = config.stderr.take(); diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs index 353ff6a57a5e..0aa4a8b139f4 100644 --- a/src/librustc_interface/lib.rs +++ b/src/librustc_interface/lib.rs @@ -18,7 +18,6 @@ extern crate libc; pub mod interface; mod passes; -mod queries; pub mod util; mod proc_macro_decls; mod profile; diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index a0ea22e7660a..16cf78a15b41 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -951,76 +951,50 @@ pub fn default_provide_extern(providers: &mut ty::query::Providers<'_>) { cstore::provide_extern(providers); } -declare_box_region_type!( - pub BoxedGlobalCtxt, - for('gcx), - (&'gcx GlobalCtxt<'gcx>) -> ((), ()) -); - -impl BoxedGlobalCtxt { - pub fn enter(&mut self, f: F) -> R - where - F: for<'tcx> FnOnce(TyCtxt<'tcx, 'tcx, 'tcx>) -> R - { - self.access(|gcx| ty::tls::enter_global(gcx, |tcx| f(tcx))) - } -} - -pub fn create_global_ctxt( +pub fn enter_global_ctxt( compiler: &Compiler, - io: InputsAndOutputs, -) -> BoxedGlobalCtxt { - let sess = compiler.session().clone(); - let cstore = compiler.cstore.clone(); + f: F, +) -> R +where + F: for<'tcx> FnOnce(&Compiler, TyCtxt<'tcx, 'tcx, 'tcx>) -> R +{ let codegen_backend = compiler.codegen_backend().clone(); - let crate_name = compiler.crate_name.clone(); + let sess = &*compiler.session(); + let cstore = &compiler.cstore.clone(); - let ((), result) = BoxedGlobalCtxt::new(static move || { - let sess = &sess; - let cstore = &cstore; + let global_ctxt: Option>; + let arenas = AllArenas::new(); - let global_ctxt: Option>; - let arenas = AllArenas::new(); + let mut local_providers = ty::query::Providers::default(); + default_provide(&mut local_providers); + codegen_backend.provide(&mut local_providers); - let mut local_providers = ty::query::Providers::default(); - default_provide(&mut local_providers); - codegen_backend.provide(&mut local_providers); + let mut extern_providers = local_providers; + default_provide_extern(&mut extern_providers); + codegen_backend.provide_extern(&mut extern_providers); - let mut extern_providers = local_providers; - default_provide_extern(&mut extern_providers); - codegen_backend.provide_extern(&mut extern_providers); - - // Move the dyn Any coercion outside the generator to avoid lifetime issues - fn codegen_backend_any( - i: Arc - ) -> Box { - Box::new(i) - } - - let gcx = TyCtxt::create_global_ctxt( - sess, - &**cstore, - cstore, - local_providers, - extern_providers, - &arenas, - crate_name, - codegen_backend_any(codegen_backend.clone()), - io, - ); + let gcx = TyCtxt::create_global_ctxt( + sess, + &**cstore, + cstore, + local_providers, + extern_providers, + &arenas, + compiler.crate_name.clone(), + Box::new(codegen_backend), + compiler.io.clone(), + ); - global_ctxt = Some(gcx); - let gcx = global_ctxt.as_ref().unwrap(); + global_ctxt = Some(gcx); + let gcx = global_ctxt.as_ref().unwrap(); - yield BoxedGlobalCtxt::initial_yield(()); - box_region_allow_access!(for('gcx), (&'gcx GlobalCtxt<'gcx>), (gcx)); + let result = ty::tls::enter_global(gcx, |tcx| f(compiler, tcx)); - gcx.queries.record_computed_queries(sess); + gcx.queries.record_computed_queries(sess); - if sess.opts.debugging_opts.query_stats { - gcx.queries.print_stats(); - } - }); + if sess.opts.debugging_opts.query_stats { + gcx.queries.print_stats(); + } result } diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs deleted file mode 100644 index 30d0d53a7f43..000000000000 --- a/src/librustc_interface/queries.rs +++ /dev/null @@ -1,153 +0,0 @@ -use crate::interface::{Compiler, Result}; -use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt}; - -use rustc_data_structures::sync::{Lrc, Lock, OneThread}; -use rustc::session::config::{Input, OutputFilenames, OutputType}; -use rustc::session::Session; -use rustc::util::common::{time, ErrorReported}; -use rustc::util::profiling::ProfileCategory; -use rustc::lint; -use rustc::hir; - use rustc::hir::def_id::{LocalCrate, LOCAL_CRATE}; -use rustc::ty; -use rustc::ty::steal::Steal; -use rustc::dep_graph::DepGraph; -use rustc_passes::hir_stats; -use rustc_plugin::registry::Registry; -use serialize::json; -use std::cell::{Ref, RefMut, RefCell}; -use std::ops::Deref; -use std::sync::Arc; -use std::sync::mpsc; -use std::any::Any; -use std::mem; -use syntax::parse::{self, PResult}; -use syntax::util::node_count::NodeCounter; -use syntax::{self, ast, attr, diagnostics, visit}; -use syntax_pos::hygiene; - -/// Represent the result of a query. -/// This result can be stolen with the `take` method and returned with the `give` method. -pub struct Query { - result: RefCell>>, -} - -impl Query { - fn compute Result>(&self, f: F) -> Result<&Query> { - let mut result = self.result.borrow_mut(); - if result.is_none() { - *result = Some(f()); - } - result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err) - } - - /// Takes ownership of the query result. Further attempts to take or peek the query - /// result will panic unless it is returned by calling the `give` method. - pub fn take(&self) -> T { - self.result - .borrow_mut() - .take() - .expect("missing query result") - .unwrap() - } - - /// Returns a stolen query result. Panics if there's already a result. - pub fn give(&self, value: T) { - let mut result = self.result.borrow_mut(); - assert!(result.is_none(), "a result already exists"); - *result = Some(Ok(value)); - } - - /// Borrows the query result using the RefCell. Panics if the result is stolen. - pub fn peek(&self) -> Ref<'_, T> { - Ref::map(self.result.borrow(), |r| { - r.as_ref().unwrap().as_ref().expect("missing query result") - }) - } - - /// Mutably borrows the query result using the RefCell. Panics if the result is stolen. - pub fn peek_mut(&self) -> RefMut<'_, T> { - RefMut::map(self.result.borrow_mut(), |r| { - r.as_mut().unwrap().as_mut().expect("missing query result") - }) - } -} - -impl Default for Query { - fn default() -> Self { - Query { - result: RefCell::new(None), - } - } -} - -#[derive(Default)] -pub(crate) struct Queries { - global_ctxt: Query, - ongoing_codegen: Query>, - link: Query<()>, -} - -impl Compiler { - pub fn global_ctxt(&self) -> Result<&Query> { - self.queries.global_ctxt.compute(|| { - Ok(passes::create_global_ctxt( - self, - self.io.clone(), - )) - }) - } - - pub fn ongoing_codegen( - &self - ) -> Result<&Query>> { - self.queries.ongoing_codegen.compute(|| { - self.global_ctxt()?.peek_mut().enter(|tcx| { - tcx.ongoing_codegen(LOCAL_CRATE) - }) - }) - } - - pub fn link(&self) -> Result<&Query<()>> { - self.queries.link.compute(|| { - let ongoing_codegen = self.ongoing_codegen()?.take(); - - self.codegen_backend().join_codegen_and_link( - OneThread::into_inner(ongoing_codegen.codegen_object.steal()), - self.session(), - &ongoing_codegen.dep_graph, - &ongoing_codegen.outputs, - ).map_err(|_| ErrorReported)?; - - Ok(()) - }) - } - - pub fn compile(&self) -> Result<()> { - self.global_ctxt()?.peek_mut().enter(|tcx| { - tcx.prepare_outputs(LocalCrate)?; - Ok(()) - })?; - - if self.session().opts.output_types.contains_key(&OutputType::DepInfo) - && self.session().opts.output_types.len() == 1 - { - return Ok(()) - } - - // Drop AST after creating GlobalCtxt to free memory - self.global_ctxt()?.peek_mut().enter(|tcx| { - tcx.lower_ast_to_hir(LocalCrate)?; - // Drop AST after lowering HIR to free memory - mem::drop(tcx.expand_macros(LocalCrate).unwrap().ast_crate.steal()); - Ok(()) - })?; - - self.ongoing_codegen()?; - - // Drop GlobalCtxt after starting codegen to free memory - mem::drop(self.global_ctxt()?.take()); - - self.link().map(|_| ()) - } -} diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 529e9fe1d8c3..cb7c04ecd3e3 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -449,7 +449,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }; interface::run_compiler_in_existing_thread_pool(config, |compiler| { - abort_on_err(compiler.global_ctxt(), compiler.session()).take().enter(|tcx| { + compiler.enter(|compiler, tcx| { let sess = compiler.session(); // We need to hold on to the complete resolver, so we cause everything to be diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index ac03f4c6fb32..136c94c83b58 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -77,7 +77,7 @@ pub fn run(options: Options) -> i32 { let display_warnings = options.display_warnings; let tests = interface::run_compiler(config, |compiler| -> Result<_, ErrorReported> { - compiler.enter(|tcx| { + compiler.enter(|compiler, tcx| { let lower_to_hir = tcx.lower_ast_to_hir(LocalCrate)?; let mut opts = scrape_test_config(lower_to_hir.forest.krate()); @@ -282,14 +282,13 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, let compile_result = panic::catch_unwind(AssertUnwindSafe(|| { interface::run_compiler(config, |compiler| { + let sess = compiler.session().clone(); if no_run { - compiler.global_ctxt().and_then(|global_ctxt| global_ctxt.take().enter(|tcx| { - tcx.analysis(LOCAL_CRATE) - })).ok(); + compiler.enter(|_, tcx| tcx.analysis(LOCAL_CRATE)).ok(); } else { compiler.compile().ok(); }; - compiler.session().compile_status() + sess.compile_status() }) })).map_err(|_| ()).and_then(|s| s.map_err(|_| ()));