about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo.net>2017-07-25 17:26:24 +0200
committerMichael Woerister <michaelwoerister@posteo.net>2017-07-31 15:15:09 +0200
commit645841ea446ed0772835f07fb62aaeecdb06b604 (patch)
tree841959cc76915629bedba9b0d42166b267475c6e /src
parent4282dd87ea79ea7836978e0b45514aea35dc1d0d (diff)
downloadrust-645841ea446ed0772835f07fb62aaeecdb06b604.tar.gz
rust-645841ea446ed0772835f07fb62aaeecdb06b604.zip
async-llvm(8): Clean up resource management and drop LLVM modules ASAP.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_driver/driver.rs2
-rw-r--r--src/librustc_trans/back/write.rs315
-rw-r--r--src/librustc_trans/base.rs27
-rw-r--r--src/librustc_trans/lib.rs63
4 files changed, 256 insertions, 151 deletions
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 1bc3f59ed04..ff9f666af75 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -237,8 +237,6 @@ pub fn compile_input(sess: &Session,
                             phase5_result);
     phase5_result?;
 
-    write::cleanup_llvm(&trans);
-
     phase_6_link_output(sess, &trans, &outputs);
 
     // Now that we won't touch anything in the incremental compilation directory
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 5d9444218c4..83f7f574493 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -18,7 +18,8 @@ use rustc::session::Session;
 use llvm;
 use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
 use llvm::SMDiagnosticRef;
-use {CrateTranslation, OngoingCrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation};
+use {CrateTranslation, OngoingCrateTranslation, ModuleSource, ModuleTranslation,
+     CompiledModule, ModuleKind};
 use rustc::hir::def_id::CrateNum;
 use rustc::util::common::{time, time_depth, set_time_depth, path2cstr};
 use rustc::util::fs::link_or_copy;
@@ -192,7 +193,6 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
 
 
 /// Module-specific configuration for `optimize_and_codegen`.
-#[derive(Clone)]
 pub struct ModuleConfig {
     /// LLVM TargetMachine to use for codegen.
     tm: TargetMachineRef,
@@ -231,9 +231,9 @@ pub struct ModuleConfig {
 unsafe impl Send for ModuleConfig { }
 
 impl ModuleConfig {
-    fn new(tm: TargetMachineRef, passes: Vec<String>) -> ModuleConfig {
+    fn new(sess: &Session, passes: Vec<String>) -> ModuleConfig {
         ModuleConfig {
-            tm: tm,
+            tm: create_target_machine(sess),
             passes: passes,
             opt_level: None,
             opt_size: None,
@@ -281,6 +281,40 @@ 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)
@@ -372,13 +406,17 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
 unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
                                diag_handler: &Handler,
                                mtrans: ModuleTranslation,
-                               mllvm: ModuleLlvm,
                                config: ModuleConfig,
                                output_names: OutputFilenames)
-    -> Result<(), FatalError>
+    -> Result<CompiledModule, FatalError>
 {
-    let llmod = mllvm.llmod;
-    let llcx = mllvm.llcx;
+    let (llmod, llcx) = match mtrans.source {
+        ModuleSource::Translated(ref llvm) => (llvm.llmod, llvm.llcx),
+        ModuleSource::Preexisting(_) => {
+            bug!("optimize_and_codegen: called with ModuleSource::Preexisting")
+        }
+    };
+
     let tm = config.tm;
 
     let fv = HandlerFreeVars {
@@ -390,7 +428,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
     llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv);
     llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, fv);
 
-    let module_name = Some(&mtrans.name[..]);
+    let module_name = mtrans.name.clone();
+    let module_name = Some(&module_name[..]);
 
     if config.emit_no_opt_bc {
         let out = output_names.temp_path_ext("no-opt.bc", module_name);
@@ -606,30 +645,13 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
         }
     }
 
-    llvm::LLVMRustDisposeTargetMachine(tm);
-    Ok(())
-}
-
-
-pub fn cleanup_llvm(trans: &CrateTranslation) {
-    for module in trans.modules.iter() {
-        unsafe {
-            match module.source {
-                ModuleSource::Translated(llvm) => {
-                    llvm::LLVMDisposeModule(llvm.llmod);
-                    llvm::LLVMContextDispose(llvm.llcx);
-                }
-                ModuleSource::Preexisting(_) => {
-                }
-            }
-        }
-    }
+    Ok(mtrans.into_compiled_module(config.emit_obj, config.emit_bc))
 }
 
-pub struct RunLLVMPassesResult {
-    pub modules: Vec<ModuleTranslation>,
-    pub metadata_module: ModuleTranslation,
-    pub allocator_module: Option<ModuleTranslation>,
+pub struct CompiledModules {
+    pub modules: Vec<CompiledModule>,
+    pub metadata_module: CompiledModule,
+    pub allocator_module: Option<CompiledModule>,
 }
 
 pub fn run_passes(sess: &Session,
@@ -658,13 +680,11 @@ pub fn run_passes(sess: &Session,
             !sess.opts.output_types.should_trans() ||
             sess.opts.debugging_opts.no_trans);
 
-    let tm = create_target_machine(sess);
-
     // Figure out what we actually need to build.
 
-    let mut modules_config = ModuleConfig::new(tm, sess.opts.cg.passes.clone());
-    let mut metadata_config = ModuleConfig::new(tm, vec![]);
-    let mut allocator_config = ModuleConfig::new(tm, vec![]);
+    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![]);
 
     if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
         match *sanitizer {
@@ -747,25 +767,22 @@ pub fn run_passes(sess: &Session,
     let mut work_items = Vec::with_capacity(1 + modules.len());
 
     {
-        let work = build_work_item(sess,
-                                   metadata_module.clone(),
-                                   metadata_config.clone(),
+        let work = build_work_item(metadata_module,
+                                   metadata_config.clone(sess),
                                    crate_output.clone());
         work_items.push(work);
     }
 
-    if let Some(allocator) = allocator_module.clone() {
-        let work = build_work_item(sess,
-                                   allocator,
-                                   allocator_config.clone(),
+    if let Some(allocator) = allocator_module {
+        let work = build_work_item(allocator,
+                                   allocator_config.clone(sess),
                                    crate_output.clone());
         work_items.push(work);
     }
 
-    for mtrans in modules.iter() {
-        let work = build_work_item(sess,
-                                   mtrans.clone(),
-                                   modules_config.clone(),
+    for mtrans in modules {
+        let work = build_work_item(mtrans,
+                                   modules_config.clone(sess),
                                    crate_output.clone());
         work_items.push(work);
     }
@@ -778,6 +795,10 @@ pub fn run_passes(sess: &Session,
         Client::new(num_workers).expect("failed to create jobserver")
     });
 
+    drop(modules_config);
+    drop(metadata_config);
+    drop(allocator_config);
+
     let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
     let (trans_worker_send, trans_worker_receive) = channel();
     let (coordinator_send, coordinator_receive) = channel();
@@ -813,37 +834,27 @@ pub fn run_passes(sess: &Session,
         }
     }
 
-    match coordinator_thread.join() {
-        Ok(()) => {},
-        Err(err) => {
-            panic!("error: {:?}", err);
-        }
-    }
+    let compiled_modules = coordinator_thread.join().unwrap();
 
     // Just in case, check this on the way out.
     shared_emitter_main.check(sess);
     sess.diagnostic().abort_if_errors();
 
     // If in incr. comp. mode, preserve the `.o` files for potential re-use
-    for mtrans in modules.iter() {
+    for module in compiled_modules.modules.iter() {
         let mut files = vec![];
 
-        if modules_config.emit_obj {
-            let path = crate_output.temp_path(OutputType::Object, Some(&mtrans.name));
+        if module.emit_obj {
+            let path = crate_output.temp_path(OutputType::Object, Some(&module.name));
             files.push((OutputType::Object, path));
         }
 
-        if modules_config.emit_bc {
-            let path = crate_output.temp_path(OutputType::Bitcode, Some(&mtrans.name));
+        if module.emit_bc {
+            let path = crate_output.temp_path(OutputType::Bitcode, Some(&module.name));
             files.push((OutputType::Bitcode, path));
         }
 
-        save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &files);
-    }
-
-    // All codegen is finished.
-    unsafe {
-        llvm::LLVMRustDisposeTargetMachine(tm);
+        save_trans_partition(sess, &module.name, module.symbol_name_hash, &files);
     }
 
     let mut user_wants_bitcode = false;
@@ -858,10 +869,10 @@ pub fn run_passes(sess: &Session,
 
         let copy_if_one_unit = |output_type: OutputType,
                                 keep_numbered: bool| {
-            if modules.len() == 1 {
+            if compiled_modules.modules.len() == 1 {
                 // 1) Only one codegen unit.  In this case it's no difficulty
                 //    to copy `foo.0.x` to `foo.x`.
-                let module_name = Some(&modules[0].name[..]);
+                let module_name = Some(&compiled_modules.modules[0].name[..]);
                 let path = crate_output.temp_path(output_type, module_name);
                 copy_gracefully(&path,
                                 &crate_output.path(output_type));
@@ -962,27 +973,30 @@ pub fn run_passes(sess: &Session,
         let keep_numbered_objects = needs_crate_object ||
                 (user_wants_objects && sess.opts.cg.codegen_units > 1);
 
-        for module_name in modules.iter().map(|m| Some(&m.name[..])) {
-            if modules_config.emit_obj && !keep_numbered_objects {
+        for module in compiled_modules.modules.iter() {
+            let module_name = Some(&module.name[..]);
+
+            if module.emit_obj && !keep_numbered_objects {
                 let path = crate_output.temp_path(OutputType::Object, module_name);
                 remove(sess, &path);
             }
 
-            if modules_config.emit_bc && !keep_numbered_bitcode {
+            if module.emit_bc && !keep_numbered_bitcode {
                 let path = crate_output.temp_path(OutputType::Bitcode, module_name);
                 remove(sess, &path);
             }
         }
 
-        if metadata_config.emit_bc && !user_wants_bitcode {
+        if compiled_modules.metadata_module.emit_bc && !user_wants_bitcode {
             let path = crate_output.temp_path(OutputType::Bitcode,
-                                              Some(&metadata_module.name));
+                                              Some(&compiled_modules.metadata_module.name));
             remove(sess, &path);
         }
-        if allocator_config.emit_bc && !user_wants_bitcode {
-            if let Some(ref module) = allocator_module {
+
+        if let Some(ref allocator_module) = compiled_modules.allocator_module {
+            if allocator_module.emit_bc && !user_wants_bitcode {
                 let path = crate_output.temp_path(OutputType::Bitcode,
-                                                  Some(&module.name));
+                                                  Some(&allocator_module.name));
                 remove(sess, &path);
             }
         }
@@ -1000,21 +1014,14 @@ pub fn run_passes(sess: &Session,
         unsafe { llvm::LLVMRustPrintPassTimings(); }
     }
 
-    *trans.result.borrow_mut() = Some(
-        RunLLVMPassesResult {
-            modules,
-            metadata_module,
-            allocator_module,
-        }
-    );
+    *trans.result.borrow_mut() = Some(compiled_modules);
 }
 
 pub fn dump_incremental_data(trans: &CrateTranslation) {
     let mut reuse = 0;
     for mtrans in trans.modules.iter() {
-        match mtrans.source {
-            ModuleSource::Preexisting(..) => reuse += 1,
-            ModuleSource::Translated(..) => (),
+        if mtrans.pre_existing {
+            reuse += 1;
         }
     }
     eprintln!("incremental: re-using {} out of {} modules", reuse, trans.modules.len());
@@ -1032,14 +1039,11 @@ impl fmt::Debug for WorkItem {
     }
 }
 
-fn build_work_item(sess: &Session,
-                   mtrans: ModuleTranslation,
+fn build_work_item(mtrans: ModuleTranslation,
                    config: ModuleConfig,
                    output_names: OutputFilenames)
                    -> WorkItem
 {
-    let mut config = config;
-    config.tm = create_target_machine(sess);
     WorkItem {
         mtrans: mtrans,
         config: config,
@@ -1048,54 +1052,65 @@ fn build_work_item(sess: &Session,
 }
 
 fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
-    -> Result<(), FatalError>
+    -> Result<CompiledModule, FatalError>
 {
     let diag_handler = cgcx.create_diag_handler();
-    unsafe {
-        match work_item.mtrans.source {
-            ModuleSource::Translated(mllvm) => {
-                debug!("llvm-optimizing {:?}", work_item.mtrans.name);
-                optimize_and_codegen(cgcx,
-                                     &diag_handler,
-                                     work_item.mtrans,
-                                     mllvm,
-                                     work_item.config,
-                                     work_item.output_names)?;
-            }
-            ModuleSource::Preexisting(wp) => {
-                let incr_comp_session_dir = cgcx.incr_comp_session_dir
-                                                .as_ref()
-                                                .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 source_file = in_incr_comp_dir(&incr_comp_session_dir,
-                                                       &saved_file);
-                    debug!("copying pre-existing module `{}` from {:?} to {}",
-                           work_item.mtrans.name,
-                           source_file,
-                           obj_out.display());
-                    match link_or_copy(&source_file, &obj_out) {
-                        Ok(_) => { }
-                        Err(err) => {
-                            diag_handler.err(&format!("unable to copy {} to {}: {}",
-                                                      source_file.display(),
-                                                      obj_out.display(),
-                                                      err));
-                        }
-                    }
+    let module_name = work_item.mtrans.name.clone();
+
+    let pre_existing = match work_item.mtrans.source {
+        ModuleSource::Translated(_) => None,
+        ModuleSource::Preexisting(ref wp) => Some(wp.clone()),
+    };
+
+    if let Some(wp) = pre_existing {
+        let incr_comp_session_dir = cgcx.incr_comp_session_dir
+                                        .as_ref()
+                                        .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 source_file = in_incr_comp_dir(&incr_comp_session_dir,
+                                               &saved_file);
+            debug!("copying pre-existing module `{}` from {:?} to {}",
+                   work_item.mtrans.name,
+                   source_file,
+                   obj_out.display());
+            match link_or_copy(&source_file, &obj_out) {
+                Ok(_) => { }
+                Err(err) => {
+                    diag_handler.err(&format!("unable to copy {} to {}: {}",
+                                              source_file.display(),
+                                              obj_out.display(),
+                                              err));
                 }
             }
         }
-    }
 
-    Ok(())
+        Ok(CompiledModule {
+            name: module_name,
+            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,
+        })
+    } else {
+        debug!("llvm-optimizing {:?}", module_name);
+
+        unsafe {
+            optimize_and_codegen(cgcx,
+                                 &diag_handler,
+                                 work_item.mtrans,
+                                 work_item.config,
+                                 work_item.output_names)
+        }
+    }
 }
 
 #[derive(Debug)]
 pub enum Message {
     Token(io::Result<Acquired>),
-    Done { success: bool },
+    Done { result: Result<CompiledModule, ()> },
     WorkItem(WorkItem),
     CheckErrorMessages,
 }
@@ -1115,7 +1130,7 @@ fn start_executing_work(sess: &Session,
                         coordinator_receive: Receiver<Message>,
                         jobserver: Client,
                         exported_symbols: Arc<ExportedSymbols>)
-                        -> thread::JoinHandle<()> {
+                        -> thread::JoinHandle<CompiledModules> {
     // 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
@@ -1215,6 +1230,10 @@ fn start_executing_work(sess: &Session,
     // the jobserver.
 
     thread::spawn(move || {
+        let mut compiled_modules = vec![];
+        let mut compiled_metadata_module = None;
+        let mut compiled_allocator_module = None;
+
         let mut work_items_left = total_work_item_count;
         let mut work_items = Vec::with_capacity(total_work_item_count);
         let mut tokens = Vec::new();
@@ -1253,7 +1272,8 @@ fn start_executing_work(sess: &Session,
                     } else {
                         shared_emitter.fatal("failed to acquire jobserver token");
                         drop(trans_worker_send.send(Message::CheckErrorMessages));
-                        return
+                        // Exit the coordinator thread
+                        panic!()
                     }
                 }
 
@@ -1269,21 +1289,42 @@ fn start_executing_work(sess: &Session,
                 //
                 // Note that if the thread failed that means it panicked, so we
                 // abort immediately.
-                Message::Done { success: true } => {
+                Message::Done { result: Ok(compiled_module) } => {
                     drop(tokens.pop());
                     running -= 1;
                     drop(trans_worker_send.send(Message::CheckErrorMessages));
+
+                    match compiled_module.kind {
+                        ModuleKind::Regular => {
+                            compiled_modules.push(compiled_module);
+                        }
+                        ModuleKind::Metadata => {
+                            assert!(compiled_metadata_module.is_none());
+                            compiled_metadata_module = Some(compiled_module);
+                        }
+                        ModuleKind::Allocator => {
+                            assert!(compiled_allocator_module.is_none());
+                            compiled_allocator_module = Some(compiled_module);
+                        }
+                    }
                 }
-                Message::Done { success: false } => {
+                Message::Done { result: Err(()) } => {
                     shared_emitter.fatal("aborting due to worker thread panic");
                     drop(trans_worker_send.send(Message::CheckErrorMessages));
-                    return
+                    // Exit the coordinator thread
+                    panic!()
                 }
                 msg @ Message::CheckErrorMessages => {
                     bug!("unexpected message: {:?}", msg);
                 }
             }
         }
+
+        CompiledModules {
+            modules: compiled_modules,
+            metadata_module: compiled_metadata_module.unwrap(),
+            allocator_module: compiled_allocator_module,
+        }
     })
 }
 
@@ -1297,17 +1338,22 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
         // we exit.
         struct Bomb {
             coordinator_send: Sender<Message>,
-            success: bool,
+            result: Option<CompiledModule>,
         }
         impl Drop for Bomb {
             fn drop(&mut self) {
-                drop(self.coordinator_send.send(Message::Done { success: self.success }));
+                let result = match self.result.take() {
+                    Some(compiled_module) => Ok(compiled_module),
+                    None => Err(())
+                };
+
+                drop(self.coordinator_send.send(Message::Done { result }));
             }
         }
 
         let mut bomb = Bomb {
             coordinator_send: cgcx.coordinator_send.clone(),
-            success: false,
+            result: None,
         };
 
         // Execute the work itself, and if it finishes successfully then flag
@@ -1323,8 +1369,7 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
         // we just ignore the result and then send off our message saying that
         // we're done, which if `execute_work_item` failed is unlikely to be
         // seen by the main thread, but hey we might as well try anyway.
-        drop(execute_work_item(&cgcx, work).is_err());
-        bomb.success = true;
+        bomb.result = Some(execute_work_item(&cgcx, work).unwrap());
     });
 }
 
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 5582079c78f..7ece92ef9dd 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -27,6 +27,7 @@ use super::OngoingCrateTranslation;
 use super::ModuleLlvm;
 use super::ModuleSource;
 use super::ModuleTranslation;
+use super::ModuleKind;
 
 use assert_module_sources;
 use back::link;
@@ -952,6 +953,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             llcx: metadata_llcx,
             llmod: metadata_llmod,
         }),
+        kind: ModuleKind::Metadata,
     };
 
     let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
@@ -961,7 +963,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
        !tcx.sess.opts.output_types.should_trans() {
         let empty_exported_symbols = ExportedSymbols::empty();
         let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols);
-        return OngoingCrateTranslation {
+        let crate_translation = OngoingCrateTranslation {
             crate_name: tcx.crate_name(LOCAL_CRATE),
             link: link_meta,
             metadata: metadata,
@@ -970,12 +972,18 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             linker_info: linker_info,
             windows_subsystem: None,
             no_integrated_as: false,
-            result: ::std::cell::RefCell::new(Some(::back::write::RunLLVMPassesResult {
-                modules: vec![],
-                metadata_module: metadata_module,
-                allocator_module: None,
-            })),
+            result: ::std::cell::RefCell::new(None),
         };
+
+        ::back::write::run_passes(tcx.sess,
+                                  &crate_translation,
+                                  vec![],
+                                  metadata_module,
+                                  None,
+                                  &output_filenames.outputs,
+                                  output_filenames);
+
+        return crate_translation;
     }
 
     let exported_symbols = Arc::new(ExportedSymbols::compute(tcx,
@@ -1047,7 +1055,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             let module = ModuleTranslation {
                 name: cgu_name,
                 symbol_name_hash,
-                source: ModuleSource::Preexisting(buf.clone())
+                source: ModuleSource::Preexisting(buf.clone()),
+                kind: ModuleKind::Regular,
             };
             return (Stats::default(), module);
         }
@@ -1108,7 +1117,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 source: ModuleSource::Translated(ModuleLlvm {
                     llcx: ccx.llcx(),
                     llmod: ccx.llmod(),
-                })
+                }),
+                kind: ModuleKind::Regular,
             }
         };
 
@@ -1196,6 +1206,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 name: link::ALLOCATOR_MODULE_NAME.to_string(),
                 symbol_name_hash: 0, // we always rebuild allocator shims
                 source: ModuleSource::Translated(modules),
+                kind: ModuleKind::Allocator,
             })
         }
     });
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index e7debe3919b..1df1bd272fd 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -135,7 +135,6 @@ mod type_;
 mod type_of;
 mod value;
 
-#[derive(Clone)]
 pub struct ModuleTranslation {
     /// The name of the module. When the crate may be saved between
     /// compilations, incremental compilation requires that name be
@@ -145,6 +144,58 @@ pub struct ModuleTranslation {
     pub name: String,
     pub symbol_name_hash: u64,
     pub source: ModuleSource,
+    pub kind: ModuleKind,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum ModuleKind {
+    Regular,
+    Metadata,
+    Allocator,
+}
+
+impl ModuleTranslation {
+    pub fn into_compiled_module(self, emit_obj: bool, emit_bc: bool) -> CompiledModule {
+        let pre_existing = match self.source {
+            ModuleSource::Preexisting(_) => true,
+            ModuleSource::Translated(_) => false,
+        };
+
+        CompiledModule {
+            name: self.name.clone(),
+            kind: self.kind,
+            symbol_name_hash: self.symbol_name_hash,
+            pre_existing,
+            emit_obj,
+            emit_bc,
+        }
+    }
+}
+
+impl Drop for ModuleTranslation {
+    fn drop(&mut self) {
+        match self.source {
+            ModuleSource::Preexisting(_) => {
+                // Nothing to dispose.
+            },
+            ModuleSource::Translated(llvm) => {
+                unsafe {
+                    llvm::LLVMDisposeModule(llvm.llmod);
+                    llvm::LLVMContextDispose(llvm.llcx);
+                }
+            },
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct CompiledModule {
+    pub name: String,
+    pub kind: ModuleKind,
+    pub symbol_name_hash: u64,
+    pub pre_existing: bool,
+    pub emit_obj: bool,
+    pub emit_bc: bool,
 }
 
 #[derive(Clone)]
@@ -156,7 +207,7 @@ pub enum ModuleSource {
     Translated(ModuleLlvm),
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub struct ModuleLlvm {
     pub llcx: llvm::ContextRef,
     pub llmod: llvm::ModuleRef,
@@ -167,9 +218,9 @@ unsafe impl Sync for ModuleTranslation { }
 
 pub struct CrateTranslation {
     pub crate_name: Symbol,
-    pub modules: Vec<ModuleTranslation>,
-    pub metadata_module: ModuleTranslation,
-    pub allocator_module: Option<ModuleTranslation>,
+    pub modules: Vec<CompiledModule>,
+    pub metadata_module: CompiledModule,
+    pub allocator_module: Option<CompiledModule>,
     pub link: rustc::middle::cstore::LinkMeta,
     pub metadata: rustc::middle::cstore::EncodedMetadata,
     pub exported_symbols: Arc<back::symbol_export::ExportedSymbols>,
@@ -189,7 +240,7 @@ pub struct OngoingCrateTranslation {
     pub no_integrated_as: bool,
 
     // This will be replaced by a Future.
-    pub result: ::std::cell::RefCell<Option<back::write::RunLLVMPassesResult>>,
+    pub result: ::std::cell::RefCell<Option<back::write::CompiledModules>>,
 }
 
 impl OngoingCrateTranslation {