about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2017-09-13 20:26:39 -0700
committerAlex Crichton <alex@alexcrichton.com>2017-09-17 10:25:50 -0700
commit6d614ddc2ebc25d3987b1efc84c0c7fea00ce325 (patch)
tree92b7f2d6ef29e86f4e09bad8b818c3f2a414a6d2
parent3021c1d0bf45d7628f6bf75aefce952ddf26193d (diff)
downloadrust-6d614ddc2ebc25d3987b1efc84c0c7fea00ce325.tar.gz
rust-6d614ddc2ebc25d3987b1efc84c0c7fea00ce325.zip
rustc: Move codegen to a query
This commit moves the actual code generation in the compiler behind a query
keyed by a codegen unit's name. This ended up entailing quite a few internal
refactorings to enable this, along with a few cut corners:

* The `OutputFilenames` structure is now tracked in the `TyCtxt` as it affects a
  whole bunch of trans and such. This is now behind a query and threaded into
  the construction of the `TyCtxt`.

* The `TyCtxt` now has a channel "out the back" intended to send data to worker
  threads in rustc_trans. This is used as a sort of side effect of the codegen
  query but morally what's happening here is the return value of the query
  (currently unit but morally a path) is only valid once the background threads
  have all finished.

* Dispatching work items to the codegen threads was refactored to only rely on
  data in `TyCtxt`, which mostly just involved refactoring where data was
  stored, moving it from the translation thread to the controller thread's
  `CodegenContext` or the like.

* A new thread locals was introduced in trans to work around the query
  system. This is used in the implementation of `assert_module_sources` which
  looks like an artifact of the old query system and will presumably go away
  once red/green is up and running.
-rw-r--r--src/librustc/dep_graph/dep_node.rs4
-rw-r--r--src/librustc/middle/trans.rs31
-rw-r--r--src/librustc/ty/context.rs10
-rw-r--r--src/librustc/ty/maps.rs39
-rw-r--r--src/librustc_driver/driver.rs25
-rw-r--r--src/librustc_driver/lib.rs1
-rw-r--r--src/librustc_driver/pretty.rs14
-rw-r--r--src/librustc_driver/test.rs14
-rw-r--r--src/librustc_trans/back/write.rs248
-rw-r--r--src/librustc_trans/base.rs433
-rw-r--r--src/librustc_trans/builder.rs9
-rw-r--r--src/librustc_trans/context.rs58
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs4
-rw-r--r--src/librustc_trans/glue.rs3
-rw-r--r--src/librustc_trans/monomorphize.rs2
-rw-r--r--src/librustc_trans/partitioning.rs9
-rw-r--r--src/librustdoc/core.rs8
17 files changed, 484 insertions, 428 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index e3a9e969864..06469c16bc2 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -71,6 +71,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 use ich::StableHashingContext;
 use std::fmt;
 use std::hash::Hash;
+use syntax_pos::symbol::InternedString;
 
 // erase!() just makes tokens go away. It's used to specify which macro argument
 // is repeated (i.e. which sub-expression of the macro we are in) but don't need
@@ -580,6 +581,9 @@ define_dep_nodes!( <'tcx>
     [] ExportName(DefId),
     [] ContainsExternIndicator(DefId),
     [] IsTranslatedFunction(DefId),
+    [] CodegenUnit(InternedString),
+    [] CompileCodegenUnit(InternedString),
+    [] OutputFilenames,
 );
 
 trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
diff --git a/src/librustc/middle/trans.rs b/src/librustc/middle/trans.rs
index cf8e9cbbd3d..9a501257548 100644
--- a/src/librustc/middle/trans.rs
+++ b/src/librustc/middle/trans.rs
@@ -77,3 +77,34 @@ impl<'tcx> CodegenUnit<'tcx> {
         &mut self.items
     }
 }
+
+#[derive(Clone, Default)]
+pub struct Stats {
+    pub n_glues_created: usize,
+    pub n_null_glues: usize,
+    pub n_real_glues: usize,
+    pub n_fns: usize,
+    pub n_inlines: usize,
+    pub n_closures: usize,
+    pub n_llvm_insns: usize,
+    pub llvm_insns: FxHashMap<String, usize>,
+    // (ident, llvm-instructions)
+    pub fn_stats: Vec<(String, usize)>,
+}
+
+impl Stats {
+    pub fn extend(&mut self, stats: Stats) {
+        self.n_glues_created += stats.n_glues_created;
+        self.n_null_glues += stats.n_null_glues;
+        self.n_real_glues += stats.n_real_glues;
+        self.n_fns += stats.n_fns;
+        self.n_inlines += stats.n_inlines;
+        self.n_closures += stats.n_closures;
+        self.n_llvm_insns += stats.n_llvm_insns;
+
+        for (k, v) in stats.llvm_insns {
+            *self.llvm_insns.entry(k).or_insert(0) += v;
+        }
+        self.fn_stats.extend(stats.fn_stats);
+    }
+}
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index e932c9728db..945a0814427 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -13,6 +13,7 @@
 use dep_graph::DepGraph;
 use errors::DiagnosticBuilder;
 use session::Session;
+use session::config::OutputFilenames;
 use middle;
 use hir::{TraitCandidate, HirId, ItemLocalId};
 use hir::def::{Def, Export};
@@ -65,6 +66,7 @@ use std::ops::Deref;
 use std::iter;
 use std::rc::Rc;
 use std::sync::mpsc;
+use std::sync::Arc;
 use syntax::abi;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
@@ -910,6 +912,8 @@ pub struct GlobalCtxt<'tcx> {
     /// when satisfying the query for a particular codegen unit. Internally in
     /// the query it'll send data along this channel to get processed later.
     pub tx_to_llvm_workers: mpsc::Sender<Box<Any + Send>>,
+
+    output_filenames: Arc<OutputFilenames>,
 }
 
 impl<'tcx> GlobalCtxt<'tcx> {
@@ -1035,6 +1039,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                   hir: hir_map::Map<'tcx>,
                                   crate_name: &str,
                                   tx: mpsc::Sender<Box<Any + Send>>,
+                                  output_filenames: &OutputFilenames,
                                   f: F) -> R
                                   where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'tcx>) -> R
     {
@@ -1156,6 +1161,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             stability_interner: RefCell::new(FxHashSet()),
             all_traits: RefCell::new(None),
             tx_to_llvm_workers: tx,
+            output_filenames: Arc::new(output_filenames.clone()),
        }, f)
     }
 
@@ -2229,4 +2235,8 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         assert_eq!(cnum, LOCAL_CRATE);
         Rc::new(tcx.cstore.postorder_cnums_untracked())
     };
+    providers.output_filenames = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        tcx.output_filenames.clone()
+    };
 }
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 307921a3335..bf17b82535c 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -24,10 +24,11 @@ use middle::resolve_lifetime::{Region, ObjectLifetimeDefault};
 use middle::stability::{self, DeprecationEntry};
 use middle::lang_items::{LanguageItems, LangItem};
 use middle::exported_symbols::SymbolExportLevel;
-use middle::trans::CodegenUnit;
+use middle::trans::{CodegenUnit, Stats};
 use mir;
 use mir::transform::{MirSuite, MirPassIndex};
 use session::CompileResult;
+use session::config::OutputFilenames;
 use traits::specialization_graph;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
 use ty::layout::{Layout, LayoutError};
@@ -52,6 +53,7 @@ use std::ops::Deref;
 use std::rc::Rc;
 use std::sync::Arc;
 use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::symbol::InternedString;
 use syntax::attr;
 use syntax::ast;
 use syntax::symbol::Symbol;
@@ -180,6 +182,15 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
     }
 }
 
+impl Key for InternedString {
+    fn map_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, _tcx: TyCtxt) -> Span {
+        DUMMY_SP
+    }
+}
+
 trait Value<'tcx>: Sized {
     fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
 }
@@ -760,6 +771,24 @@ impl<'tcx> QueryDescription for queries::collect_and_partition_translation_items
     }
 }
 
+impl<'tcx> QueryDescription for queries::codegen_unit<'tcx> {
+    fn describe(_tcx: TyCtxt, _: InternedString) -> String {
+        format!("codegen_unit")
+    }
+}
+
+impl<'tcx> QueryDescription for queries::compile_codegen_unit<'tcx> {
+    fn describe(_tcx: TyCtxt, _: InternedString) -> String {
+        format!("compile_codegen_unit")
+    }
+}
+
+impl<'tcx> QueryDescription for queries::output_filenames<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("output_filenames")
+    }
+}
+
 // If enabled, send a message to the profile-queries thread
 macro_rules! profq_msg {
     ($tcx:expr, $msg:expr) => {
@@ -1395,6 +1424,10 @@ define_maps! { <'tcx>
     [] fn export_name: ExportName(DefId) -> Option<Symbol>,
     [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool,
     [] fn is_translated_function: IsTranslatedFunction(DefId) -> bool,
+    [] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
+    [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
+    [] fn output_filenames: output_filenames_node(CrateNum)
+        -> Arc<OutputFilenames>,
 }
 
 fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
@@ -1512,3 +1545,7 @@ fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
 fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
     DepConstructor::CollectAndPartitionTranslationItems
 }
+
+fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+    DepConstructor::OutputFilenames
+}
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 0adcfa79039..32a160bcffc 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -193,6 +193,7 @@ pub fn compile_input(sess: &Session,
                                                                   &resolutions,
                                                                   &expanded_crate,
                                                                   &hir_map.krate(),
+                                                                  &outputs,
                                                                   &crate_name),
                                     Ok(()));
         }
@@ -216,6 +217,7 @@ pub fn compile_input(sess: &Session,
                                     &arena,
                                     &arenas,
                                     &crate_name,
+                                    &outputs,
                                     |tcx, analysis, incremental_hashes_map, rx, result| {
             {
                 // Eventually, we will want to track plugins.
@@ -246,8 +248,7 @@ pub fn compile_input(sess: &Session,
 
             let trans = phase_4_translate_to_llvm(tcx,
                                                   incremental_hashes_map,
-                                                  rx,
-                                                  &outputs);
+                                                  rx);
 
             if log_enabled!(::log::LogLevel::Info) {
                 println!("Post-trans");
@@ -261,7 +262,7 @@ pub fn compile_input(sess: &Session,
                 }
             }
 
-            Ok((outputs, trans, tcx.dep_graph.clone()))
+            Ok((outputs.clone(), trans, tcx.dep_graph.clone()))
         })??
     };
 
@@ -486,6 +487,7 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> {
                                 resolutions: &'a Resolutions,
                                 krate: &'a ast::Crate,
                                 hir_crate: &'a hir::Crate,
+                                output_filenames: &'a OutputFilenames,
                                 crate_name: &'a str)
                                 -> Self {
         CompileState {
@@ -498,6 +500,7 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> {
             resolutions: Some(resolutions),
             expanded_crate: Some(krate),
             hir_crate: Some(hir_crate),
+            output_filenames: Some(output_filenames),
             out_file: out_file.as_ref().map(|s| &**s),
             ..CompileState::empty(input, session, out_dir)
         }
@@ -913,6 +916,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                                                arena: &'tcx DroplessArena,
                                                arenas: &'tcx GlobalArenas<'tcx>,
                                                name: &str,
+                                               output_filenames: &OutputFilenames,
                                                f: F)
                                                -> Result<R, CompileIncomplete>
     where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>,
@@ -922,11 +926,11 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                             CompileResult) -> R
 {
     macro_rules! try_with_f {
-        ($e: expr, ($t: expr, $a: expr, $h: expr)) => {
+        ($e: expr, ($($t:tt)*)) => {
             match $e {
                 Ok(x) => x,
                 Err(x) => {
-                    f($t, $a, $h, Err(x));
+                    f($($t)*, Err(x));
                     return Err(x);
                 }
             }
@@ -1047,6 +1051,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                              hir_map,
                              name,
                              tx,
+                             output_filenames,
                              |tcx| {
         let incremental_hashes_map =
             time(time_passes,
@@ -1062,7 +1067,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
              || stability::check_unstable_api_usage(tcx));
 
         // passes are timed inside typeck
-        try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map));
+        try_with_f!(typeck::check_crate(tcx),
+                    (tcx, analysis, incremental_hashes_map, rx));
 
         time(time_passes,
              "const checking",
@@ -1106,7 +1112,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
         // lint warnings and so on -- kindck used to do this abort, but
         // kindck is gone now). -nmatsakis
         if sess.err_count() > 0 {
-            return Ok(f(tcx, analysis, incremental_hashes_map, sess.compile_status()));
+            return Ok(f(tcx, analysis, incremental_hashes_map, rx, sess.compile_status()));
         }
 
         time(time_passes, "death checking", || middle::dead::check_crate(tcx));
@@ -1125,8 +1131,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 /// be discarded.
 pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                            incremental_hashes_map: IncrementalHashesMap,
-                                           rx: mpsc::Receiver<Box<Any + Send>>,
-                                           output_filenames: &OutputFilenames)
+                                           rx: mpsc::Receiver<Box<Any + Send>>)
                                            -> write::OngoingCrateTranslation {
     let time_passes = tcx.sess.time_passes();
 
@@ -1136,7 +1141,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let translation =
         time(time_passes, "translation", move || {
-            trans::trans_crate(tcx, incremental_hashes_map, rx, output_filenames)
+            trans::trans_crate(tcx, incremental_hashes_map, rx)
         });
 
     if tcx.sess.profile_queries() {
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 522b9eb2232..044f4a5eaf5 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -645,6 +645,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
                                                      ppm,
                                                      state.arena.unwrap(),
                                                      state.arenas.unwrap(),
+                                                     state.output_filenames.unwrap(),
                                                      opt_uii.clone(),
                                                      state.out_file);
                 };
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 82dda2d2aa1..cd153b82077 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -23,7 +23,7 @@ use rustc::cfg::graphviz::LabelledCFG;
 use rustc::dep_graph::DepGraph;
 use rustc::middle::cstore::CrateStore;
 use rustc::session::Session;
-use rustc::session::config::Input;
+use rustc::session::config::{Input, OutputFilenames};
 use rustc_borrowck as borrowck;
 use rustc_borrowck::graphviz as borrowck_dot;
 
@@ -205,6 +205,7 @@ impl PpSourceMode {
                                                resolutions: &Resolutions,
                                                arena: &'tcx DroplessArena,
                                                arenas: &'tcx GlobalArenas<'tcx>,
+                                               output_filenames: &OutputFilenames,
                                                id: &str,
                                                f: F)
                                                -> A
@@ -235,7 +236,8 @@ impl PpSourceMode {
                                                                  arena,
                                                                  arenas,
                                                                  id,
-                                                                 |tcx, _, _, _| {
+                                                                 output_filenames,
+                                                                 |tcx, _, _, _, _| {
                     let empty_tables = ty::TypeckTables::empty(None);
                     let annotation = TypedAnnotation {
                         tcx,
@@ -888,6 +890,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                 ppm: PpMode,
                                                 arena: &'tcx DroplessArena,
                                                 arenas: &'tcx GlobalArenas<'tcx>,
+                                                output_filenames: &OutputFilenames,
                                                 opt_uii: Option<UserIdentifiedItem>,
                                                 ofile: Option<&Path>) {
     let dep_graph = DepGraph::new(false);
@@ -902,6 +905,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                             crate_name,
                             arena,
                             arenas,
+                            output_filenames,
                             ppm,
                             opt_uii,
                             ofile);
@@ -940,6 +944,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                            resolutions,
                                            arena,
                                            arenas,
+                                           output_filenames,
                                            crate_name,
                                            move |annotation, krate| {
                     debug!("pretty printing source code {:?}", s);
@@ -964,6 +969,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                            resolutions,
                                            arena,
                                            arenas,
+                                           output_filenames,
                                            crate_name,
                                            move |annotation, _| {
                     debug!("pretty printing source code {:?}", s);
@@ -1007,6 +1013,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                        crate_name: &str,
                                        arena: &'tcx DroplessArena,
                                        arenas: &'tcx GlobalArenas<'tcx>,
+                                       output_filenames: &OutputFilenames,
                                        ppm: PpMode,
                                        uii: Option<UserIdentifiedItem>,
                                        ofile: Option<&Path>) {
@@ -1028,7 +1035,8 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                      arena,
                                                      arenas,
                                                      crate_name,
-                                                     |tcx, _, _, _| {
+                                                     output_filenames,
+                                                     |tcx, _, _, _, _| {
         match ppm {
             PpmMir | PpmMirCFG => {
                 if let Some(nodeid) = nodeid {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index d0edcbc3260..34f4e0e7b0c 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -10,6 +10,9 @@
 
 //! # Standalone Tests for the Inference Module
 
+use std::path::PathBuf;
+use std::sync::mpsc;
+
 use driver;
 use rustc_lint;
 use rustc_resolve::MakeGlobMap;
@@ -26,6 +29,7 @@ use rustc_metadata::cstore::CStore;
 use rustc::hir::map as hir_map;
 use rustc::mir::transform::Passes;
 use rustc::session::{self, config};
+use rustc::session::config::{OutputFilenames, OutputTypes};
 use std::rc::Rc;
 use syntax::ast;
 use syntax::abi::Abi;
@@ -133,6 +137,14 @@ fn test_env<F>(source_string: &str,
 
     // run just enough stuff to build a tcx:
     let named_region_map = resolve_lifetime::krate(&sess, &*cstore, &hir_map);
+    let (tx, _rx) = mpsc::channel();
+    let outputs = OutputFilenames {
+        out_directory: PathBuf::new(),
+        out_filestem: String::new(),
+        single_output_file: None,
+        extra: String::new(),
+        outputs: OutputTypes::new(&[]),
+    };
     TyCtxt::create_and_enter(&sess,
                              &*cstore,
                              ty::maps::Providers::default(),
@@ -144,6 +156,8 @@ fn test_env<F>(source_string: &str,
                              named_region_map.unwrap(),
                              hir_map,
                              "test_crate",
+                             tx,
+                             &outputs,
                              |tcx| {
         tcx.infer_ctxt().enter(|infcx| {
             let mut region_scope_tree = region::ScopeTree::default();
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 2535583cc6f..ef6bf2504f3 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -203,8 +203,6 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
 
 /// Module-specific configuration for `optimize_and_codegen`.
 pub struct ModuleConfig {
-    /// LLVM TargetMachine to use for codegen.
-    tm: TargetMachineRef,
     /// Names of additional optimization passes to run.
     passes: Vec<String>,
     /// Some(level) to optimize at a certain level, or None to run
@@ -237,12 +235,9 @@ pub struct ModuleConfig {
     obj_is_bitcode: bool,
 }
 
-unsafe impl Send for ModuleConfig { }
-
 impl ModuleConfig {
-    fn new(sess: &Session, passes: Vec<String>) -> ModuleConfig {
+    fn new(passes: Vec<String>) -> ModuleConfig {
         ModuleConfig {
-            tm: create_target_machine(sess),
             passes,
             opt_level: None,
             opt_size: None,
@@ -290,40 +285,6 @@ impl ModuleConfig {
         self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
                                sess.opts.optimize == config::OptLevel::Aggressive;
     }
-
-    fn clone(&self, sess: &Session) -> ModuleConfig {
-        ModuleConfig {
-            tm: create_target_machine(sess),
-            passes: self.passes.clone(),
-            opt_level: self.opt_level,
-            opt_size: self.opt_size,
-
-            emit_no_opt_bc: self.emit_no_opt_bc,
-            emit_bc: self.emit_bc,
-            emit_lto_bc: self.emit_lto_bc,
-            emit_ir: self.emit_ir,
-            emit_asm: self.emit_asm,
-            emit_obj: self.emit_obj,
-            obj_is_bitcode: self.obj_is_bitcode,
-
-            no_verify: self.no_verify,
-            no_prepopulate_passes: self.no_prepopulate_passes,
-            no_builtins: self.no_builtins,
-            time_passes: self.time_passes,
-            vectorize_loop: self.vectorize_loop,
-            vectorize_slp: self.vectorize_slp,
-            merge_functions: self.merge_functions,
-            inline_threshold: self.inline_threshold,
-        }
-    }
-}
-
-impl Drop for ModuleConfig {
-    fn drop(&mut self) {
-        unsafe {
-            llvm::LLVMRustDisposeTargetMachine(self.tm);
-        }
-    }
 }
 
 /// Additional resources used by optimize_and_codegen (not module specific)
@@ -337,6 +298,11 @@ pub struct CodegenContext {
     pub opts: Arc<config::Options>,
     pub crate_types: Vec<config::CrateType>,
     pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>,
+    output_filenames: Arc<OutputFilenames>,
+    regular_module_config: Arc<ModuleConfig>,
+    metadata_module_config: Arc<ModuleConfig>,
+    allocator_module_config: Arc<ModuleConfig>,
+
     // Handler to use for diagnostics produced during codegen.
     pub diag_emitter: SharedEmitter,
     // LLVM passes added by plugins.
@@ -359,6 +325,14 @@ impl CodegenContext {
     fn create_diag_handler(&self) -> Handler {
         Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone()))
     }
+
+    fn config(&self, kind: ModuleKind) -> &ModuleConfig {
+        match kind {
+            ModuleKind::Regular => &self.regular_module_config,
+            ModuleKind::Metadata => &self.metadata_module_config,
+            ModuleKind::Allocator => &self.allocator_module_config,
+        }
+    }
 }
 
 struct HandlerFreeVars<'a> {
@@ -418,8 +392,8 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
 unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
                                diag_handler: &Handler,
                                mtrans: ModuleTranslation,
-                               config: ModuleConfig,
-                               output_names: OutputFilenames)
+                               tm: TargetMachineRef,
+                               config: &ModuleConfig)
     -> Result<CompiledModule, FatalError>
 {
     let (llmod, llcx) = match mtrans.source {
@@ -429,8 +403,6 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
         }
     };
 
-    let tm = config.tm;
-
     let fv = HandlerFreeVars {
         cgcx,
         diag_handler,
@@ -444,7 +416,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
     let module_name = Some(&module_name[..]);
 
     if config.emit_no_opt_bc {
-        let out = output_names.temp_path_ext("no-opt.bc", module_name);
+        let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
         let out = path2cstr(&out);
         llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
     }
@@ -517,7 +489,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
         if cgcx.lto {
             time(cgcx.time_passes, "all lto passes", || {
                 let temp_no_opt_bc_filename =
-                    output_names.temp_path_ext("no-opt.lto.bc", module_name);
+                    cgcx.output_filenames.temp_path_ext("no-opt.lto.bc", module_name);
                 lto::run(cgcx,
                          diag_handler,
                          llmod,
@@ -526,7 +498,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
                          &temp_no_opt_bc_filename)
             })?;
             if config.emit_lto_bc {
-                let out = output_names.temp_path_ext("lto.bc", module_name);
+                let out = cgcx.output_filenames.temp_path_ext("lto.bc", module_name);
                 let out = path2cstr(&out);
                 llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
             }
@@ -562,8 +534,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
     let write_obj = config.emit_obj && !config.obj_is_bitcode;
     let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode;
 
-    let bc_out = output_names.temp_path(OutputType::Bitcode, module_name);
-    let obj_out = output_names.temp_path(OutputType::Object, module_name);
+    let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
+    let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
 
     if write_bc {
         let bc_out_c = path2cstr(&bc_out);
@@ -573,7 +545,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
     time(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()),
          || -> Result<(), FatalError> {
         if config.emit_ir {
-            let out = output_names.temp_path(OutputType::LlvmAssembly, module_name);
+            let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
             let out = path2cstr(&out);
 
             extern "C" fn demangle_callback(input_ptr: *const c_char,
@@ -614,7 +586,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
         }
 
         if config.emit_asm {
-            let path = output_names.temp_path(OutputType::Assembly, module_name);
+            let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
 
             // We can't use the same module for asm and binary output, because that triggers
             // various errors like invalid IR or broken binaries, so we might have to clone the
@@ -672,13 +644,13 @@ fn need_crate_bitcode_for_rlib(sess: &Session) -> bool {
 }
 
 pub fn start_async_translation(tcx: TyCtxt,
-                               crate_output: &OutputFilenames,
                                time_graph: Option<TimeGraph>,
                                link: LinkMeta,
                                metadata: EncodedMetadata,
                                coordinator_receive: Receiver<Box<Any + Send>>)
                                -> OngoingCrateTranslation {
     let sess = tcx.sess;
+    let crate_output = tcx.output_filenames(LOCAL_CRATE);
     let crate_name = tcx.crate_name(LOCAL_CRATE);
     let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins");
     let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs,
@@ -699,13 +671,6 @@ pub fn start_async_translation(tcx: TyCtxt,
     let linker_info = LinkerInfo::new(tcx);
     let crate_info = CrateInfo::new(tcx);
 
-    let mut exported_symbols = FxHashMap();
-    exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE));
-    for &cnum in tcx.crates().iter() {
-        exported_symbols.insert(cnum, tcx.exported_symbols(cnum));
-    }
-    let exported_symbols = Arc::new(exported_symbols);
-
     let output_types_override = if no_integrated_as {
         OutputTypes::new(&[(OutputType::Assembly, None)])
     } else {
@@ -713,9 +678,9 @@ pub fn start_async_translation(tcx: TyCtxt,
     };
 
     // Figure out what we actually need to build.
-    let mut modules_config = ModuleConfig::new(sess, sess.opts.cg.passes.clone());
-    let mut metadata_config = ModuleConfig::new(sess, vec![]);
-    let mut allocator_config = ModuleConfig::new(sess, vec![]);
+    let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone());
+    let mut metadata_config = ModuleConfig::new(vec![]);
+    let mut allocator_config = ModuleConfig::new(vec![]);
 
     if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
         match *sanitizer {
@@ -801,15 +766,17 @@ pub fn start_async_translation(tcx: TyCtxt,
     let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
     let (trans_worker_send, trans_worker_receive) = channel();
 
-    let coordinator_thread = start_executing_work(sess,
+    let coordinator_thread = start_executing_work(tcx,
                                                   &crate_info,
                                                   shared_emitter,
                                                   trans_worker_send,
-                                                  tcx.tx_to_llvm_workers.clone(),
                                                   coordinator_receive,
                                                   client,
                                                   time_graph.clone(),
-                                                  exported_symbols.clone());
+                                                  Arc::new(modules_config),
+                                                  Arc::new(metadata_config),
+                                                  Arc::new(allocator_config));
+
     OngoingCrateTranslation {
         crate_name,
         link,
@@ -819,16 +786,12 @@ pub fn start_async_translation(tcx: TyCtxt,
         no_integrated_as,
         crate_info,
 
-        regular_module_config: modules_config,
-        metadata_module_config: metadata_config,
-        allocator_module_config: allocator_config,
-
         time_graph,
-        output_filenames: crate_output.clone(),
         coordinator_send: tcx.tx_to_llvm_workers.clone(),
         trans_worker_receive,
         shared_emitter_main,
-        future: coordinator_thread
+        future: coordinator_thread,
+        output_filenames: tcx.output_filenames(LOCAL_CRATE),
     }
 }
 
@@ -1029,8 +992,7 @@ pub fn dump_incremental_data(trans: &CrateTranslation) {
 
 struct WorkItem {
     mtrans: ModuleTranslation,
-    config: ModuleConfig,
-    output_names: OutputFilenames
+    tm: TargetMachine,
 }
 
 impl fmt::Debug for WorkItem {
@@ -1039,15 +1001,15 @@ impl fmt::Debug for WorkItem {
     }
 }
 
-fn build_work_item(mtrans: ModuleTranslation,
-                   config: ModuleConfig,
-                   output_names: OutputFilenames)
-                   -> WorkItem
-{
-    WorkItem {
-        mtrans,
-        config,
-        output_names,
+struct TargetMachine(TargetMachineRef);
+
+unsafe impl Send for TargetMachine {}
+
+impl Drop for TargetMachine {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMRustDisposeTargetMachine(self.0);
+        }
     }
 }
 
@@ -1056,6 +1018,7 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
 {
     let diag_handler = cgcx.create_diag_handler();
     let module_name = work_item.mtrans.name.clone();
+    let config = cgcx.config(work_item.mtrans.kind);
 
     let pre_existing = match work_item.mtrans.source {
         ModuleSource::Translated(_) => None,
@@ -1068,7 +1031,7 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
                                         .unwrap();
         let name = &work_item.mtrans.name;
         for (kind, saved_file) in wp.saved_files {
-            let obj_out = work_item.output_names.temp_path(kind, Some(name));
+            let obj_out = cgcx.output_filenames.temp_path(kind, Some(name));
             let source_file = in_incr_comp_dir(&incr_comp_session_dir,
                                                &saved_file);
             debug!("copying pre-existing module `{}` from {:?} to {}",
@@ -1091,8 +1054,8 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
             kind: ModuleKind::Regular,
             pre_existing: true,
             symbol_name_hash: work_item.mtrans.symbol_name_hash,
-            emit_bc: work_item.config.emit_bc,
-            emit_obj: work_item.config.emit_obj,
+            emit_bc: config.emit_bc,
+            emit_obj: config.emit_obj,
         })
     } else {
         debug!("llvm-optimizing {:?}", module_name);
@@ -1101,8 +1064,8 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
             optimize_and_codegen(cgcx,
                                  &diag_handler,
                                  work_item.mtrans,
-                                 work_item.config,
-                                 work_item.output_names)
+                                 work_item.tm.0,
+                                 config)
         }
     }
 }
@@ -1117,8 +1080,8 @@ enum Message {
     TranslationDone {
         llvm_work_item: WorkItem,
         cost: u64,
-        is_last: bool,
     },
+    TranslationComplete,
     TranslateItem,
 }
 
@@ -1135,16 +1098,26 @@ enum MainThreadWorkerState {
     LLVMing,
 }
 
-fn start_executing_work(sess: &Session,
+fn start_executing_work(tcx: TyCtxt,
                         crate_info: &CrateInfo,
                         shared_emitter: SharedEmitter,
                         trans_worker_send: Sender<Message>,
-                        coordinator_send: Sender<Box<Any + Send>>,
                         coordinator_receive: Receiver<Box<Any + Send>>,
                         jobserver: Client,
                         time_graph: Option<TimeGraph>,
-                        exported_symbols: Arc<ExportedSymbols>)
+                        modules_config: Arc<ModuleConfig>,
+                        metadata_config: Arc<ModuleConfig>,
+                        allocator_config: Arc<ModuleConfig>)
                         -> thread::JoinHandle<CompiledModules> {
+    let coordinator_send = tcx.tx_to_llvm_workers.clone();
+    let mut exported_symbols = FxHashMap();
+    exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE));
+    for &cnum in tcx.crates().iter() {
+        exported_symbols.insert(cnum, tcx.exported_symbols(cnum));
+    }
+    let exported_symbols = Arc::new(exported_symbols);
+    let sess = tcx.sess;
+
     // First up, convert our jobserver into a helper thread so we can use normal
     // mpsc channels to manage our messages and such. Once we've got the helper
     // thread then request `n-1` tokens because all of our work items are ready
@@ -1183,6 +1156,10 @@ fn start_executing_work(sess: &Session,
         coordinator_send,
         diag_emitter: shared_emitter.clone(),
         time_graph,
+        output_filenames: tcx.output_filenames(LOCAL_CRATE),
+        regular_module_config: modules_config,
+        metadata_module_config: metadata_config,
+        allocator_module_config: allocator_config,
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
@@ -1332,7 +1309,7 @@ fn start_executing_work(sess: &Session,
         let mut translation_done = false;
 
         // This is the queue of LLVM work items that still need processing.
-        let mut work_items = Vec::new();
+        let mut work_items = Vec::<(WorkItem, u64)>::new();
 
         // This are the Jobserver Tokens we currently hold. Does not include
         // the implicit Token the compiler process owns no matter what.
@@ -1371,7 +1348,8 @@ fn start_executing_work(sess: &Session,
                             worker: get_worker_id(&mut free_worker_ids),
                             .. cgcx.clone()
                         };
-                        maybe_start_llvm_timer(&item, &mut llvm_start_time);
+                        maybe_start_llvm_timer(cgcx.config(item.mtrans.kind),
+                                               &mut llvm_start_time);
                         main_thread_worker_state = MainThreadWorkerState::LLVMing;
                         spawn_work(cgcx, item);
                     }
@@ -1387,7 +1365,8 @@ fn start_executing_work(sess: &Session,
                                 worker: get_worker_id(&mut free_worker_ids),
                                 .. cgcx.clone()
                             };
-                            maybe_start_llvm_timer(&item, &mut llvm_start_time);
+                            maybe_start_llvm_timer(cgcx.config(item.mtrans.kind),
+                                                   &mut llvm_start_time);
                             main_thread_worker_state = MainThreadWorkerState::LLVMing;
                             spawn_work(cgcx, item);
                         } else {
@@ -1417,7 +1396,8 @@ fn start_executing_work(sess: &Session,
             while work_items.len() > 0 && running < tokens.len() {
                 let (item, _) = work_items.pop().unwrap();
 
-                maybe_start_llvm_timer(&item, &mut llvm_start_time);
+                maybe_start_llvm_timer(cgcx.config(item.mtrans.kind),
+                                       &mut llvm_start_time);
 
                 let cgcx = CodegenContext {
                     worker: get_worker_id(&mut free_worker_ids),
@@ -1459,7 +1439,7 @@ fn start_executing_work(sess: &Session,
                     }
                 }
 
-                Message::TranslationDone { llvm_work_item, cost, is_last } => {
+                Message::TranslationDone { llvm_work_item, cost } => {
                     // We keep the queue sorted by estimated processing cost,
                     // so that more expensive items are processed earlier. This
                     // is good for throughput as it gives the main thread more
@@ -1475,15 +1455,14 @@ fn start_executing_work(sess: &Session,
                     };
                     work_items.insert(insertion_index, (llvm_work_item, cost));
 
-                    if is_last {
-                        // If this is the last, don't request a token because
-                        // the trans worker thread will be free to handle this
-                        // immediately.
-                        translation_done = true;
-                    } else {
-                        helper.request_token();
-                    }
+                    helper.request_token();
+                    assert_eq!(main_thread_worker_state,
+                               MainThreadWorkerState::Translating);
+                    main_thread_worker_state = MainThreadWorkerState::Idle;
+                }
 
+                Message::TranslationComplete => {
+                    translation_done = true;
                     assert_eq!(main_thread_worker_state,
                                MainThreadWorkerState::Translating);
                     main_thread_worker_state = MainThreadWorkerState::Idle;
@@ -1561,11 +1540,11 @@ fn start_executing_work(sess: &Session,
         items_in_queue >= max_workers.saturating_sub(workers_running / 2)
     }
 
-    fn maybe_start_llvm_timer(work_item: &WorkItem,
+    fn maybe_start_llvm_timer(config: &ModuleConfig,
                               llvm_start_time: &mut Option<Instant>) {
         // We keep track of the -Ztime-passes output manually,
         // since the closure-based interface does not fit well here.
-        if work_item.config.time_passes {
+        if config.time_passes {
             if llvm_start_time.is_none() {
                 *llvm_start_time = Some(Instant::now());
             }
@@ -1840,17 +1819,12 @@ pub struct OngoingCrateTranslation {
     linker_info: LinkerInfo,
     no_integrated_as: bool,
     crate_info: CrateInfo,
-
-    output_filenames: OutputFilenames,
-    regular_module_config: ModuleConfig,
-    metadata_module_config: ModuleConfig,
-    allocator_module_config: ModuleConfig,
-
     time_graph: Option<TimeGraph>,
     coordinator_send: Sender<Box<Any + Send>>,
     trans_worker_receive: Receiver<Message>,
     shared_emitter_main: SharedEmitterMain,
     future: thread::JoinHandle<CompiledModules>,
+    output_filenames: Arc<OutputFilenames>,
 }
 
 impl OngoingCrateTranslation {
@@ -1918,38 +1892,21 @@ impl OngoingCrateTranslation {
         trans
     }
 
-    pub fn submit_translated_module_to_llvm(&self,
-                                            sess: &Session,
-                                            mtrans: ModuleTranslation,
-                                            cost: u64,
-                                            is_last: bool) {
-        let module_config = match mtrans.kind {
-            ModuleKind::Regular => self.regular_module_config.clone(sess),
-            ModuleKind::Metadata => self.metadata_module_config.clone(sess),
-            ModuleKind::Allocator => self.allocator_module_config.clone(sess),
-        };
-
-        let llvm_work_item = build_work_item(mtrans,
-                                             module_config,
-                                             self.output_filenames.clone());
-
-        drop(self.coordinator_send.send(Box::new(Message::TranslationDone {
-            llvm_work_item,
-            cost,
-            is_last
-        })));
-    }
-
     pub fn submit_pre_translated_module_to_llvm(&self,
-                                                sess: &Session,
-                                                mtrans: ModuleTranslation,
-                                                is_last: bool) {
+                                                tcx: TyCtxt,
+                                                mtrans: ModuleTranslation) {
         self.wait_for_signal_to_translate_item();
-        self.check_for_errors(sess);
+        self.check_for_errors(tcx.sess);
 
         // These are generally cheap and won't through off scheduling.
         let cost = 0;
-        self.submit_translated_module_to_llvm(sess, mtrans, cost, is_last);
+        submit_translated_module_to_llvm(tcx, mtrans, cost);
+    }
+
+    pub fn translation_finished(&self, tcx: TyCtxt) {
+        self.wait_for_signal_to_translate_item();
+        self.check_for_errors(tcx.sess);
+        drop(self.coordinator_send.send(Box::new(Message::TranslationComplete)));
     }
 
     pub fn check_for_errors(&self, sess: &Session) {
@@ -1971,3 +1928,16 @@ impl OngoingCrateTranslation {
         }
     }
 }
+
+pub fn submit_translated_module_to_llvm(tcx: TyCtxt,
+                                        mtrans: ModuleTranslation,
+                                        cost: u64) {
+    let llvm_work_item = WorkItem {
+        mtrans,
+        tm: TargetMachine(create_target_machine(tcx.sess)),
+    };
+    drop(tcx.tx_to_llvm_workers.send(Box::new(Message::TranslationDone {
+        llvm_work_item,
+        cost,
+    })));
+}
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 1b802f74201..d86f88d4c7d 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -28,7 +28,7 @@ use super::ModuleSource;
 use super::ModuleTranslation;
 use super::ModuleKind;
 
-use assert_module_sources;
+use assert_module_sources::{self, Disposition};
 use back::link;
 use back::symbol_export;
 use back::write::{self, OngoingCrateTranslation};
@@ -37,7 +37,7 @@ use llvm;
 use metadata;
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::middle::lang_items::StartFnLangItem;
-use rustc::middle::trans::{Linkage, Visibility};
+use rustc::middle::trans::{Linkage, Visibility, Stats};
 use rustc::middle::cstore::{EncodedMetadata, EncodedMetadataHashes};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
@@ -45,7 +45,7 @@ use rustc::dep_graph::AssertDepGraphSafe;
 use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
 use rustc::hir::map as hir_map;
 use rustc::util::common::{time, print_time_passes_entry};
-use rustc::session::config::{self, NoDebugInfo, OutputFilenames};
+use rustc::session::config::{self, NoDebugInfo};
 use rustc::session::Session;
 use rustc_incremental::{self, IncrementalHashesMap};
 use abi;
@@ -61,7 +61,7 @@ use common::CrateContext;
 use common::{type_is_zero_size, val_ty};
 use common;
 use consts;
-use context::{self, LocalCrateContext, SharedCrateContext, Stats};
+use context::{self, LocalCrateContext, SharedCrateContext};
 use debuginfo;
 use declare;
 use machine;
@@ -80,6 +80,7 @@ use CrateInfo;
 
 use libc::c_uint;
 use std::any::Any;
+use std::cell::RefCell;
 use std::ffi::{CStr, CString};
 use std::str;
 use std::sync::Arc;
@@ -87,6 +88,7 @@ use std::time::{Instant, Duration};
 use std::i32;
 use std::sync::mpsc;
 use syntax_pos::Span;
+use syntax_pos::symbol::InternedString;
 use syntax::attr;
 use rustc::hir;
 use syntax::ast;
@@ -101,7 +103,7 @@ pub struct StatRecorder<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> StatRecorder<'a, 'tcx> {
     pub fn new(ccx: &'a CrateContext<'a, 'tcx>, name: String) -> StatRecorder<'a, 'tcx> {
-        let istart = ccx.stats().n_llvm_insns.get();
+        let istart = ccx.stats().borrow().n_llvm_insns;
         StatRecorder {
             ccx,
             name: Some(name),
@@ -113,12 +115,12 @@ impl<'a, 'tcx> StatRecorder<'a, 'tcx> {
 impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
     fn drop(&mut self) {
         if self.ccx.sess().trans_stats() {
-            let iend = self.ccx.stats().n_llvm_insns.get();
-            self.ccx.stats().fn_stats.borrow_mut()
-                .push((self.name.take().unwrap(), iend - self.istart));
-            self.ccx.stats().n_fns.set(self.ccx.stats().n_fns.get() + 1);
+            let mut stats = self.ccx.stats().borrow_mut();
+            let iend = stats.n_llvm_insns;
+            stats.fn_stats.push((self.name.take().unwrap(), iend - self.istart));
+            stats.n_fns += 1;
             // Reset LLVM insn count to avoid compound costs.
-            self.ccx.stats().n_llvm_insns.set(self.istart);
+            stats.n_llvm_insns = self.istart;
         }
     }
 }
@@ -590,7 +592,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
         None => bug!("Instance `{:?}` not already declared", instance)
     };
 
-    ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
+    ccx.stats().borrow_mut().n_closures += 1;
 
     // The `uwtable` attribute according to LLVM is:
     //
@@ -935,18 +937,14 @@ pub fn find_exported_symbols(tcx: TyCtxt) -> NodeSet {
 
 pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              incremental_hashes_map: IncrementalHashesMap,
-                             rx: mpsc::Receiver<Box<Any + Send>>,
-                             output_filenames: &OutputFilenames)
+                             rx: mpsc::Receiver<Box<Any + Send>>)
                              -> OngoingCrateTranslation {
     check_for_rustc_errors_attr(tcx);
 
-    let check_overflow = tcx.sess.overflow_checks();
     let link_meta = link::build_link_meta(&incremental_hashes_map);
     let exported_symbol_node_ids = find_exported_symbols(tcx);
 
-    let shared_ccx = SharedCrateContext::new(tcx,
-                                             check_overflow,
-                                             output_filenames);
+    let shared_ccx = SharedCrateContext::new(tcx);
     // Translate the metadata.
     let (metadata_llcx, metadata_llmod, metadata, metadata_incr_hashes) =
         time(tcx.sess.time_passes(), "write metadata", || {
@@ -974,13 +972,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
        !tcx.sess.opts.output_types.should_trans() {
         let ongoing_translation = write::start_async_translation(
             tcx,
-            output_filenames,
             time_graph.clone(),
             link_meta,
             metadata,
             rx);
 
-        ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, metadata_module, true);
+        ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module);
+        ongoing_translation.translation_finished(tcx);
 
         assert_and_save_dep_graph(tcx,
                                   incremental_hashes_map,
@@ -1002,7 +1000,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let ongoing_translation = write::start_async_translation(
         tcx,
-        output_filenames,
         time_graph.clone(),
         link_meta,
         metadata,
@@ -1044,16 +1041,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     };
 
     if let Some(allocator_module) = allocator_module {
-        ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, allocator_module, false);
+        ongoing_translation.submit_pre_translated_module_to_llvm(tcx, allocator_module);
     }
 
-    let codegen_unit_count = codegen_units.len();
-    ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess,
-                                                             metadata_module,
-                                                             codegen_unit_count == 0);
-
-    let mut all_stats = Stats::default();
-    let mut module_dispositions = tcx.sess.opts.incremental.as_ref().map(|_| Vec::new());
+    ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module);
 
     // We sort the codegen units by size. This way we can schedule work for LLVM
     // a bit more efficiently. Note that "size" is defined rather crudely at the
@@ -1066,217 +1057,57 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     };
 
     let mut total_trans_time = Duration::new(0, 0);
+    let mut all_stats = Stats::default();
 
-    for (cgu_index, cgu) in codegen_units.into_iter().enumerate() {
+    for cgu in codegen_units.into_iter() {
         ongoing_translation.wait_for_signal_to_translate_item();
         ongoing_translation.check_for_errors(tcx.sess);
 
+        let _timing_guard = time_graph
+            .as_ref()
+            .map(|time_graph| time_graph.start(write::TRANS_WORKER_TIMELINE,
+                                               write::TRANS_WORK_PACKAGE_KIND));
         let start_time = Instant::now();
+        all_stats.extend(tcx.compile_codegen_unit(*cgu.name()));
+        total_trans_time += start_time.elapsed();
 
-        let module = {
-            let _timing_guard = time_graph
-                .as_ref()
-                .map(|time_graph| time_graph.start(write::TRANS_WORKER_TIMELINE,
-                                                   write::TRANS_WORK_PACKAGE_KIND));
-            let dep_node = cgu.work_product_dep_node();
-            let ((stats, module), _) =
-                tcx.dep_graph.with_task(dep_node,
-                                        AssertDepGraphSafe(&shared_ccx),
-                                        AssertDepGraphSafe(cgu),
-                                        module_translation);
-            all_stats.extend(stats);
-
-            if let Some(ref mut module_dispositions) = module_dispositions {
-                module_dispositions.push(module.disposition());
-            }
-
-            module
-        };
-
-        let time_to_translate = Instant::now().duration_since(start_time);
-
-        // We assume that the cost to run LLVM on a CGU is proportional to
-        // the time we needed for translating it.
-        let cost = time_to_translate.as_secs() * 1_000_000_000 +
-                   time_to_translate.subsec_nanos() as u64;
-
-        total_trans_time += time_to_translate;
-
-        let is_last_cgu = (cgu_index + 1) == codegen_unit_count;
-
-        ongoing_translation.submit_translated_module_to_llvm(tcx.sess,
-                                                             module,
-                                                             cost,
-                                                             is_last_cgu);
         ongoing_translation.check_for_errors(tcx.sess);
     }
 
+    ongoing_translation.translation_finished(tcx);
+
     // Since the main thread is sometimes blocked during trans, we keep track
     // -Ztime-passes output manually.
     print_time_passes_entry(tcx.sess.time_passes(),
                             "translate to LLVM IR",
                             total_trans_time);
 
-    if let Some(module_dispositions) = module_dispositions {
-        assert_module_sources::assert_module_sources(tcx, &module_dispositions);
-    }
-
-    fn module_translation<'a, 'tcx>(
-        scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>,
-        args: AssertDepGraphSafe<Arc<CodegenUnit<'tcx>>>)
-        -> (Stats, ModuleTranslation)
-    {
-        // FIXME(#40304): We ought to be using the id as a key and some queries, I think.
-        let AssertDepGraphSafe(scx) = scx;
-        let AssertDepGraphSafe(cgu) = args;
-
-        let cgu_name = cgu.name().to_string();
-        let cgu_id = cgu.work_product_id();
-        let symbol_name_hash = cgu.compute_symbol_name_hash(scx);
-
-        // Check whether there is a previous work-product we can
-        // re-use.  Not only must the file exist, and the inputs not
-        // be dirty, but the hash of the symbols we will generate must
-        // be the same.
-        let previous_work_product =
-            scx.dep_graph().previous_work_product(&cgu_id).and_then(|work_product| {
-                if work_product.input_hash == symbol_name_hash {
-                    debug!("trans_reuse_previous_work_products: reusing {:?}", work_product);
-                    Some(work_product)
-                } else {
-                    if scx.sess().opts.debugging_opts.incremental_info {
-                        eprintln!("incremental: CGU `{}` invalidated because of \
-                                   changed partitioning hash.",
-                                   cgu.name());
-                    }
-                    debug!("trans_reuse_previous_work_products: \
-                            not reusing {:?} because hash changed to {:?}",
-                           work_product, symbol_name_hash);
-                    None
-                }
-            });
-
-        if let Some(buf) = previous_work_product {
-            // Don't need to translate this module.
-            let module = ModuleTranslation {
-                name: cgu_name,
-                symbol_name_hash,
-                source: ModuleSource::Preexisting(buf.clone()),
-                kind: ModuleKind::Regular,
-            };
-            return (Stats::default(), module);
-        }
-
-        // Instantiate translation items without filling out definitions yet...
-        let lcx = LocalCrateContext::new(scx, cgu);
-        let module = {
-            let ccx = CrateContext::new(scx, &lcx);
-            let trans_items = ccx.codegen_unit()
-                                 .items_in_deterministic_order(ccx.tcx());
-            for &(trans_item, (linkage, visibility)) in &trans_items {
-                trans_item.predefine(&ccx, linkage, visibility);
-            }
-
-            // ... and now that we have everything pre-defined, fill out those definitions.
-            for &(trans_item, _) in &trans_items {
-                trans_item.define(&ccx);
-            }
-
-            // If this codegen unit contains the main function, also create the
-            // wrapper here
-            maybe_create_entry_wrapper(&ccx);
-
-            // Run replace-all-uses-with for statics that need it
-            for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() {
-                unsafe {
-                    let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g));
-                    llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
-                    llvm::LLVMDeleteGlobal(old_g);
-                }
-            }
-
-            // Create the llvm.used variable
-            // This variable has type [N x i8*] and is stored in the llvm.metadata section
-            if !ccx.used_statics().borrow().is_empty() {
-                let name = CString::new("llvm.used").unwrap();
-                let section = CString::new("llvm.metadata").unwrap();
-                let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow());
-
-                unsafe {
-                    let g = llvm::LLVMAddGlobal(ccx.llmod(),
-                                                val_ty(array).to_ref(),
-                                                name.as_ptr());
-                    llvm::LLVMSetInitializer(g, array);
-                    llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
-                    llvm::LLVMSetSection(g, section.as_ptr());
-                }
-            }
-
-            // Finalize debuginfo
-            if ccx.sess().opts.debuginfo != NoDebugInfo {
-                debuginfo::finalize(&ccx);
-            }
-
-            let llvm_module = ModuleLlvm {
-                llcx: ccx.llcx(),
-                llmod: ccx.llmod(),
-            };
-
-            // In LTO mode we inject the allocator shim into the existing
-            // module.
-            if ccx.sess().lto() {
-                if let Some(kind) = ccx.sess().allocator_kind.get() {
-                    time(ccx.sess().time_passes(), "write allocator module", || {
-                        unsafe {
-                            allocator::trans(ccx.tcx(), &llvm_module, kind);
-                        }
-                    });
-                }
-            }
-
-            // Adjust exported symbols for MSVC dllimport
-            if ccx.sess().target.target.options.is_like_msvc &&
-               ccx.sess().crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
-                create_imps(ccx.sess(), &llvm_module);
-            }
-
-            ModuleTranslation {
-                name: cgu_name,
-                symbol_name_hash,
-                source: ModuleSource::Translated(llvm_module),
-                kind: ModuleKind::Regular,
-            }
-        };
-
-        (lcx.into_stats(), module)
+    if tcx.sess.opts.incremental.is_some() {
+        DISPOSITIONS.with(|d| {
+            assert_module_sources::assert_module_sources(tcx, &d.borrow());
+        });
     }
 
     symbol_names_test::report_symbol_names(tcx);
 
     if shared_ccx.sess().trans_stats() {
         println!("--- trans stats ---");
-        println!("n_glues_created: {}", all_stats.n_glues_created.get());
-        println!("n_null_glues: {}", all_stats.n_null_glues.get());
-        println!("n_real_glues: {}", all_stats.n_real_glues.get());
+        println!("n_glues_created: {}", all_stats.n_glues_created);
+        println!("n_null_glues: {}", all_stats.n_null_glues);
+        println!("n_real_glues: {}", all_stats.n_real_glues);
 
-        println!("n_fns: {}", all_stats.n_fns.get());
-        println!("n_inlines: {}", all_stats.n_inlines.get());
-        println!("n_closures: {}", all_stats.n_closures.get());
+        println!("n_fns: {}", all_stats.n_fns);
+        println!("n_inlines: {}", all_stats.n_inlines);
+        println!("n_closures: {}", all_stats.n_closures);
         println!("fn stats:");
-        all_stats.fn_stats.borrow_mut().sort_by(|&(_, insns_a), &(_, insns_b)| {
-            insns_b.cmp(&insns_a)
-        });
-        for tuple in all_stats.fn_stats.borrow().iter() {
-            match *tuple {
-                (ref name, insns) => {
-                    println!("{} insns, {}", insns, *name);
-                }
-            }
+        all_stats.fn_stats.sort_by_key(|&(_, insns)| insns);
+        for &(ref name, insns) in all_stats.fn_stats.iter() {
+            println!("{} insns, {}", insns, *name);
         }
     }
 
     if shared_ccx.sess().count_llvm_insns() {
-        for (k, v) in all_stats.llvm_insns.borrow().iter() {
+        for (k, v) in all_stats.llvm_insns.iter() {
             println!("{:7} {}", *v, *k);
         }
     }
@@ -1290,6 +1121,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     ongoing_translation
 }
 
+// FIXME(#42293) hopefully once red/green is enabled we're testing everything
+// via a method that doesn't require this!
+thread_local!(static DISPOSITIONS: RefCell<Vec<(String, Disposition)>> = Default::default());
+
 fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        incremental_hashes_map: IncrementalHashesMap,
                                        metadata_incr_hashes: EncodedMetadataHashes,
@@ -1524,11 +1359,185 @@ fn is_translated_function(tcx: TyCtxt, id: DefId) -> bool {
     })
 }
 
+fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                  cgu: InternedString) -> Stats {
+    // FIXME(#42293) needs red/green tracking to avoid failing a bunch of
+    // existing tests
+    let cgu = tcx.dep_graph.with_ignore(|| {
+        tcx.codegen_unit(cgu)
+    });
+
+    let start_time = Instant::now();
+    let dep_node = cgu.work_product_dep_node();
+    let ((stats, module), _) =
+        tcx.dep_graph.with_task(dep_node,
+                                AssertDepGraphSafe(tcx),
+                                AssertDepGraphSafe(cgu),
+                                module_translation);
+    let time_to_translate = start_time.elapsed();
+
+    if tcx.sess.opts.incremental.is_some() {
+        DISPOSITIONS.with(|d| {
+            d.borrow_mut().push(module.disposition());
+        });
+    }
+
+    // We assume that the cost to run LLVM on a CGU is proportional to
+    // the time we needed for translating it.
+    let cost = time_to_translate.as_secs() * 1_000_000_000 +
+               time_to_translate.subsec_nanos() as u64;
+
+    write::submit_translated_module_to_llvm(tcx,
+                                            module,
+                                            cost);
+    return stats;
+
+    fn module_translation<'a, 'tcx>(
+        tcx: AssertDepGraphSafe<TyCtxt<'a, 'tcx, 'tcx>>,
+        args: AssertDepGraphSafe<Arc<CodegenUnit<'tcx>>>)
+        -> (Stats, ModuleTranslation)
+    {
+        // FIXME(#40304): We ought to be using the id as a key and some queries, I think.
+        let AssertDepGraphSafe(tcx) = tcx;
+        let AssertDepGraphSafe(cgu) = args;
+
+        let cgu_name = cgu.name().to_string();
+        let cgu_id = cgu.work_product_id();
+        let symbol_name_hash = cgu.compute_symbol_name_hash(tcx);
+
+        // Check whether there is a previous work-product we can
+        // re-use.  Not only must the file exist, and the inputs not
+        // be dirty, but the hash of the symbols we will generate must
+        // be the same.
+        let previous_work_product =
+            tcx.dep_graph.previous_work_product(&cgu_id).and_then(|work_product| {
+                if work_product.input_hash == symbol_name_hash {
+                    debug!("trans_reuse_previous_work_products: reusing {:?}", work_product);
+                    Some(work_product)
+                } else {
+                    if tcx.sess.opts.debugging_opts.incremental_info {
+                        eprintln!("incremental: CGU `{}` invalidated because of \
+                                   changed partitioning hash.",
+                                   cgu.name());
+                    }
+                    debug!("trans_reuse_previous_work_products: \
+                            not reusing {:?} because hash changed to {:?}",
+                           work_product, symbol_name_hash);
+                    None
+                }
+            });
+
+        if let Some(buf) = previous_work_product {
+            // Don't need to translate this module.
+            let module = ModuleTranslation {
+                name: cgu_name,
+                symbol_name_hash,
+                source: ModuleSource::Preexisting(buf.clone()),
+                kind: ModuleKind::Regular,
+            };
+            return (Stats::default(), module);
+        }
+
+        // Instantiate translation items without filling out definitions yet...
+        let scx = SharedCrateContext::new(tcx);
+        let lcx = LocalCrateContext::new(&scx, cgu);
+        let module = {
+            let ccx = CrateContext::new(&scx, &lcx);
+            let trans_items = ccx.codegen_unit()
+                                 .items_in_deterministic_order(ccx.tcx());
+            for &(trans_item, (linkage, visibility)) in &trans_items {
+                trans_item.predefine(&ccx, linkage, visibility);
+            }
+
+            // ... and now that we have everything pre-defined, fill out those definitions.
+            for &(trans_item, _) in &trans_items {
+                trans_item.define(&ccx);
+            }
+
+            // If this codegen unit contains the main function, also create the
+            // wrapper here
+            maybe_create_entry_wrapper(&ccx);
+
+            // Run replace-all-uses-with for statics that need it
+            for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() {
+                unsafe {
+                    let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g));
+                    llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
+                    llvm::LLVMDeleteGlobal(old_g);
+                }
+            }
+
+            // Create the llvm.used variable
+            // This variable has type [N x i8*] and is stored in the llvm.metadata section
+            if !ccx.used_statics().borrow().is_empty() {
+                let name = CString::new("llvm.used").unwrap();
+                let section = CString::new("llvm.metadata").unwrap();
+                let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow());
+
+                unsafe {
+                    let g = llvm::LLVMAddGlobal(ccx.llmod(),
+                                                val_ty(array).to_ref(),
+                                                name.as_ptr());
+                    llvm::LLVMSetInitializer(g, array);
+                    llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+                    llvm::LLVMSetSection(g, section.as_ptr());
+                }
+            }
+
+            // Finalize debuginfo
+            if ccx.sess().opts.debuginfo != NoDebugInfo {
+                debuginfo::finalize(&ccx);
+            }
+
+            let llvm_module = ModuleLlvm {
+                llcx: ccx.llcx(),
+                llmod: ccx.llmod(),
+            };
+
+            // In LTO mode we inject the allocator shim into the existing
+            // module.
+            if ccx.sess().lto() {
+                if let Some(kind) = ccx.sess().allocator_kind.get() {
+                    time(ccx.sess().time_passes(), "write allocator module", || {
+                        unsafe {
+                            allocator::trans(ccx.tcx(), &llvm_module, kind);
+                        }
+                    });
+                }
+            }
+
+            // Adjust exported symbols for MSVC dllimport
+            if ccx.sess().target.target.options.is_like_msvc &&
+               ccx.sess().crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
+                create_imps(ccx.sess(), &llvm_module);
+            }
+
+            ModuleTranslation {
+                name: cgu_name,
+                symbol_name_hash,
+                source: ModuleSource::Translated(llvm_module),
+                kind: ModuleKind::Regular,
+            }
+        };
+
+        (lcx.into_stats(), module)
+    }
+}
+
 pub fn provide_local(providers: &mut Providers) {
     providers.collect_and_partition_translation_items =
         collect_and_partition_translation_items;
 
     providers.is_translated_function = is_translated_function;
+
+    providers.codegen_unit = |tcx, name| {
+        let (_, all) = tcx.collect_and_partition_translation_items(LOCAL_CRATE);
+        all.iter()
+            .find(|cgu| *cgu.name() == name)
+            .cloned()
+            .expect(&format!("failed to find cgu with name {:?}", name))
+    };
+    providers.compile_codegen_unit = compile_codegen_unit;
 }
 
 pub fn provide_extern(providers: &mut Providers) {
diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs
index 8a585e72f59..41a238ea8e3 100644
--- a/src/librustc_trans/builder.rs
+++ b/src/librustc_trans/builder.rs
@@ -101,11 +101,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     fn count_insn(&self, category: &str) {
         if self.ccx.sess().trans_stats() {
-            self.ccx.stats().n_llvm_insns.set(self.ccx.stats().n_llvm_insns.get() + 1);
+            self.ccx.stats().borrow_mut().n_llvm_insns += 1;
         }
         if self.ccx.sess().count_llvm_insns() {
-            let mut h = self.ccx.stats().llvm_insns.borrow_mut();
-            *h.entry(category.to_string()).or_insert(0) += 1;
+            *self.ccx.stats()
+                .borrow_mut()
+                .llvm_insns
+                .entry(category.to_string())
+                .or_insert(0) += 1;
         }
     }
 
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index a1666fa5231..8b18bf2e1ff 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -24,10 +24,11 @@ use monomorphize::Instance;
 use partitioning::CodegenUnit;
 use type_::Type;
 use rustc_data_structures::base_n;
-use rustc::session::config::{self, NoDebugInfo, OutputFilenames};
+use rustc::middle::trans::Stats;
 use rustc::session::Session;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::session::config::{self, NoDebugInfo};
 use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util::nodemap::FxHashMap;
 
 use std::ffi::{CStr, CString};
@@ -40,36 +41,6 @@ use std::marker::PhantomData;
 use syntax::symbol::InternedString;
 use abi::Abi;
 
-#[derive(Clone, Default)]
-pub struct Stats {
-    pub n_glues_created: Cell<usize>,
-    pub n_null_glues: Cell<usize>,
-    pub n_real_glues: Cell<usize>,
-    pub n_fns: Cell<usize>,
-    pub n_inlines: Cell<usize>,
-    pub n_closures: Cell<usize>,
-    pub n_llvm_insns: Cell<usize>,
-    pub llvm_insns: RefCell<FxHashMap<String, usize>>,
-    // (ident, llvm-instructions)
-    pub fn_stats: RefCell<Vec<(String, usize)> >,
-}
-
-impl Stats {
-    pub fn extend(&mut self, stats: Stats) {
-        self.n_glues_created.set(self.n_glues_created.get() + stats.n_glues_created.get());
-        self.n_null_glues.set(self.n_null_glues.get() + stats.n_null_glues.get());
-        self.n_real_glues.set(self.n_real_glues.get() + stats.n_real_glues.get());
-        self.n_fns.set(self.n_fns.get() + stats.n_fns.get());
-        self.n_inlines.set(self.n_inlines.get() + stats.n_inlines.get());
-        self.n_closures.set(self.n_closures.get() + stats.n_closures.get());
-        self.n_llvm_insns.set(self.n_llvm_insns.get() + stats.n_llvm_insns.get());
-        self.llvm_insns.borrow_mut().extend(
-            stats.llvm_insns.borrow().iter()
-                                     .map(|(key, value)| (key.clone(), value.clone())));
-        self.fn_stats.borrow_mut().append(&mut *stats.fn_stats.borrow_mut());
-    }
-}
-
 /// The shared portion of a `CrateContext`.  There is one `SharedCrateContext`
 /// per crate.  The data here is shared between all compilation units of the
 /// crate, so it must not contain references to any LLVM data structures
@@ -77,10 +48,7 @@ impl Stats {
 pub struct SharedCrateContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     check_overflow: bool,
-
     use_dll_storage_attrs: bool,
-
-    output_filenames: &'a OutputFilenames,
 }
 
 /// The local portion of a `CrateContext`.  There is one `LocalCrateContext`
@@ -90,7 +58,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
 pub struct LocalCrateContext<'a, 'tcx: 'a> {
     llmod: ModuleRef,
     llcx: ContextRef,
-    stats: Stats,
+    stats: RefCell<Stats>,
     codegen_unit: Arc<CodegenUnit<'tcx>>,
 
     /// Cache instances of monomorphic and polymorphic items
@@ -253,10 +221,7 @@ pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (Cont
 }
 
 impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
-    pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
-               check_overflow: bool,
-               output_filenames: &'b OutputFilenames)
-               -> SharedCrateContext<'b, 'tcx> {
+    pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>) -> SharedCrateContext<'b, 'tcx> {
         // An interesting part of Windows which MSVC forces our hand on (and
         // apparently MinGW didn't) is the usage of `dllimport` and `dllexport`
         // attributes in LLVM IR as well as native dependencies (in C these
@@ -302,11 +267,12 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         // start) and then strongly recommending static linkage on MSVC!
         let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc;
 
+        let check_overflow = tcx.sess.overflow_checks();
+
         SharedCrateContext {
             tcx,
             check_overflow,
             use_dll_storage_attrs,
-            output_filenames,
         }
     }
 
@@ -337,10 +303,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
     pub fn use_dll_storage_attrs(&self) -> bool {
         self.use_dll_storage_attrs
     }
-
-    pub fn output_filenames(&self) -> &OutputFilenames {
-        self.output_filenames
-    }
 }
 
 impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
@@ -375,7 +337,7 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
             let local_ccx = LocalCrateContext {
                 llmod,
                 llcx,
-                stats: Stats::default(),
+                stats: RefCell::new(Stats::default()),
                 codegen_unit,
                 instances: RefCell::new(FxHashMap()),
                 vtables: RefCell::new(FxHashMap()),
@@ -440,7 +402,7 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
     }
 
     pub fn into_stats(self) -> Stats {
-        self.stats
+        self.stats.into_inner()
     }
 }
 
@@ -525,7 +487,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.local().lltypes
     }
 
-    pub fn stats<'a>(&'a self) -> &'a Stats {
+    pub fn stats<'a>(&'a self) -> &'a RefCell<Stats> {
         &self.local().stats
     }
 
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 333f7b1c029..8a89bfee4ac 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -822,9 +822,9 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
 
             let gcov_cu_info = [
                 path_to_mdstring(debug_context.llcontext,
-                                 &scc.output_filenames().with_extension("gcno")),
+                                 &scc.tcx().output_filenames(LOCAL_CRATE).with_extension("gcno")),
                 path_to_mdstring(debug_context.llcontext,
-                                 &scc.output_filenames().with_extension("gcda")),
+                                 &scc.tcx().output_filenames(LOCAL_CRATE).with_extension("gcda")),
                 cu_desc_metadata,
             ];
             let gcov_metadata = llvm::LLVMMDNodeInContext(debug_context.llcontext,
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 1572f1dc230..453b98a1d74 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -20,9 +20,8 @@ use llvm::{ValueRef};
 use llvm;
 use meth;
 use monomorphize;
-use rustc::traits;
 use rustc::ty::layout::LayoutTyper;
-use rustc::ty::{self, Ty, TypeFoldable, TyCtxt};
+use rustc::ty::{self, Ty};
 use value::Value;
 
 pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef)
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs
index e62924a54d7..2be7a81b1cd 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans/monomorphize.rs
@@ -187,7 +187,7 @@ pub fn resolve<'a, 'tcx>(
             _ => {
                 if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
                     let ty = substs.type_at(0);
-                    if common::type_needs_drop(tcx, ty) {
+                    if type_needs_drop(tcx, ty) {
                         debug!(" => nontrivial drop glue");
                         ty::InstanceDef::DropGlue(def_id, Some(ty))
                     } else {
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index 65cf24e8c6e..9b617c35d93 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -104,7 +104,6 @@
 
 use collector::InliningMap;
 use common;
-use context::SharedCrateContext;
 use rustc::dep_graph::{DepNode, WorkProductId};
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
@@ -155,13 +154,11 @@ pub trait CodegenUnitExt<'tcx> {
         self.work_product_id().to_dep_node()
     }
 
-    fn compute_symbol_name_hash<'a>(&self,
-                                    scx: &SharedCrateContext<'a, 'tcx>)
-                                    -> u64 {
+    fn compute_symbol_name_hash<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> u64 {
         let mut state = IchHasher::new();
-        let all_items = self.items_in_deterministic_order(scx.tcx());
+        let all_items = self.items_in_deterministic_order(tcx);
         for (item, (linkage, visibility)) in all_items {
-            let symbol_name = item.symbol_name(scx.tcx());
+            let symbol_name = item.symbol_name(tcx);
             symbol_name.len().hash(&mut state);
             symbol_name.hash(&mut state);
             linkage.hash(&mut state);
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index fd0167be2b9..0c0748cf673 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -176,6 +176,11 @@ pub fn run_core(search_paths: SearchPaths,
     let arena = DroplessArena::new();
     let arenas = GlobalArenas::new();
     let hir_map = hir_map::map_crate(&mut hir_forest, defs);
+    let output_filenames = driver::build_output_filenames(&input,
+                                                          &None,
+                                                          &None,
+                                                          &[],
+                                                          &sess);
 
     abort_on_err(driver::phase_3_run_analysis_passes(&sess,
                                                      &*cstore,
@@ -185,7 +190,8 @@ pub fn run_core(search_paths: SearchPaths,
                                                      &arena,
                                                      &arenas,
                                                      &name,
-                                                     |tcx, analysis, _, result| {
+                                                     &output_filenames,
+                                                     |tcx, analysis, _, _, result| {
         if let Err(_) = result {
             sess.fatal("Compilation failed, aborting rustdoc");
         }