1
Fork 0

async-llvm(8): Clean up resource management and drop LLVM modules ASAP.

This commit is contained in:
Michael Woerister 2017-07-25 17:26:24 +02:00
parent 4282dd87ea
commit 645841ea44
4 changed files with 256 additions and 151 deletions

View file

@ -237,8 +237,6 @@ pub fn compile_input(sess: &Session,
phase5_result); phase5_result);
phase5_result?; phase5_result?;
write::cleanup_llvm(&trans);
phase_6_link_output(sess, &trans, &outputs); phase_6_link_output(sess, &trans, &outputs);
// Now that we won't touch anything in the incremental compilation directory // Now that we won't touch anything in the incremental compilation directory

View file

@ -18,7 +18,8 @@ use rustc::session::Session;
use llvm; use llvm;
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef}; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
use llvm::SMDiagnosticRef; use llvm::SMDiagnosticRef;
use {CrateTranslation, OngoingCrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation}; use {CrateTranslation, OngoingCrateTranslation, ModuleSource, ModuleTranslation,
CompiledModule, ModuleKind};
use rustc::hir::def_id::CrateNum; use rustc::hir::def_id::CrateNum;
use rustc::util::common::{time, time_depth, set_time_depth, path2cstr}; use rustc::util::common::{time, time_depth, set_time_depth, path2cstr};
use rustc::util::fs::link_or_copy; 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`. /// Module-specific configuration for `optimize_and_codegen`.
#[derive(Clone)]
pub struct ModuleConfig { pub struct ModuleConfig {
/// LLVM TargetMachine to use for codegen. /// LLVM TargetMachine to use for codegen.
tm: TargetMachineRef, tm: TargetMachineRef,
@ -231,9 +231,9 @@ pub struct ModuleConfig {
unsafe impl Send for ModuleConfig { } unsafe impl Send for ModuleConfig { }
impl ModuleConfig { impl ModuleConfig {
fn new(tm: TargetMachineRef, passes: Vec<String>) -> ModuleConfig { fn new(sess: &Session, passes: Vec<String>) -> ModuleConfig {
ModuleConfig { ModuleConfig {
tm: tm, tm: create_target_machine(sess),
passes: passes, passes: passes,
opt_level: None, opt_level: None,
opt_size: None, opt_size: None,
@ -281,6 +281,40 @@ impl ModuleConfig {
self.merge_functions = sess.opts.optimize == config::OptLevel::Default || self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
sess.opts.optimize == config::OptLevel::Aggressive; 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) /// 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, unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
diag_handler: &Handler, diag_handler: &Handler,
mtrans: ModuleTranslation, mtrans: ModuleTranslation,
mllvm: ModuleLlvm,
config: ModuleConfig, config: ModuleConfig,
output_names: OutputFilenames) output_names: OutputFilenames)
-> Result<(), FatalError> -> Result<CompiledModule, FatalError>
{ {
let llmod = mllvm.llmod; let (llmod, llcx) = match mtrans.source {
let llcx = mllvm.llcx; ModuleSource::Translated(ref llvm) => (llvm.llmod, llvm.llcx),
ModuleSource::Preexisting(_) => {
bug!("optimize_and_codegen: called with ModuleSource::Preexisting")
}
};
let tm = config.tm; let tm = config.tm;
let fv = HandlerFreeVars { let fv = HandlerFreeVars {
@ -390,7 +428,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv); llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv);
llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_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 { if config.emit_no_opt_bc {
let out = output_names.temp_path_ext("no-opt.bc", module_name); 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(mtrans.into_compiled_module(config.emit_obj, config.emit_bc))
Ok(())
} }
pub struct CompiledModules {
pub fn cleanup_llvm(trans: &CrateTranslation) { pub modules: Vec<CompiledModule>,
for module in trans.modules.iter() { pub metadata_module: CompiledModule,
unsafe { pub allocator_module: Option<CompiledModule>,
match module.source {
ModuleSource::Translated(llvm) => {
llvm::LLVMDisposeModule(llvm.llmod);
llvm::LLVMContextDispose(llvm.llcx);
}
ModuleSource::Preexisting(_) => {
}
}
}
}
}
pub struct RunLLVMPassesResult {
pub modules: Vec<ModuleTranslation>,
pub metadata_module: ModuleTranslation,
pub allocator_module: Option<ModuleTranslation>,
} }
pub fn run_passes(sess: &Session, pub fn run_passes(sess: &Session,
@ -658,13 +680,11 @@ pub fn run_passes(sess: &Session,
!sess.opts.output_types.should_trans() || !sess.opts.output_types.should_trans() ||
sess.opts.debugging_opts.no_trans); sess.opts.debugging_opts.no_trans);
let tm = create_target_machine(sess);
// Figure out what we actually need to build. // Figure out what we actually need to build.
let mut modules_config = ModuleConfig::new(tm, sess.opts.cg.passes.clone()); let mut modules_config = ModuleConfig::new(sess, sess.opts.cg.passes.clone());
let mut metadata_config = ModuleConfig::new(tm, vec![]); let mut metadata_config = ModuleConfig::new(sess, vec![]);
let mut allocator_config = ModuleConfig::new(tm, vec![]); let mut allocator_config = ModuleConfig::new(sess, vec![]);
if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer { if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
match *sanitizer { match *sanitizer {
@ -747,25 +767,22 @@ pub fn run_passes(sess: &Session,
let mut work_items = Vec::with_capacity(1 + modules.len()); let mut work_items = Vec::with_capacity(1 + modules.len());
{ {
let work = build_work_item(sess, let work = build_work_item(metadata_module,
metadata_module.clone(), metadata_config.clone(sess),
metadata_config.clone(),
crate_output.clone()); crate_output.clone());
work_items.push(work); work_items.push(work);
} }
if let Some(allocator) = allocator_module.clone() { if let Some(allocator) = allocator_module {
let work = build_work_item(sess, let work = build_work_item(allocator,
allocator, allocator_config.clone(sess),
allocator_config.clone(),
crate_output.clone()); crate_output.clone());
work_items.push(work); work_items.push(work);
} }
for mtrans in modules.iter() { for mtrans in modules {
let work = build_work_item(sess, let work = build_work_item(mtrans,
mtrans.clone(), modules_config.clone(sess),
modules_config.clone(),
crate_output.clone()); crate_output.clone());
work_items.push(work); work_items.push(work);
} }
@ -778,6 +795,10 @@ pub fn run_passes(sess: &Session,
Client::new(num_workers).expect("failed to create jobserver") 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 (shared_emitter, shared_emitter_main) = SharedEmitter::new();
let (trans_worker_send, trans_worker_receive) = channel(); let (trans_worker_send, trans_worker_receive) = channel();
let (coordinator_send, coordinator_receive) = channel(); let (coordinator_send, coordinator_receive) = channel();
@ -813,37 +834,27 @@ pub fn run_passes(sess: &Session,
} }
} }
match coordinator_thread.join() { let compiled_modules = coordinator_thread.join().unwrap();
Ok(()) => {},
Err(err) => {
panic!("error: {:?}", err);
}
}
// Just in case, check this on the way out. // Just in case, check this on the way out.
shared_emitter_main.check(sess); shared_emitter_main.check(sess);
sess.diagnostic().abort_if_errors(); sess.diagnostic().abort_if_errors();
// If in incr. comp. mode, preserve the `.o` files for potential re-use // 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![]; let mut files = vec![];
if modules_config.emit_obj { if module.emit_obj {
let path = crate_output.temp_path(OutputType::Object, Some(&mtrans.name)); let path = crate_output.temp_path(OutputType::Object, Some(&module.name));
files.push((OutputType::Object, path)); files.push((OutputType::Object, path));
} }
if modules_config.emit_bc { if module.emit_bc {
let path = crate_output.temp_path(OutputType::Bitcode, Some(&mtrans.name)); let path = crate_output.temp_path(OutputType::Bitcode, Some(&module.name));
files.push((OutputType::Bitcode, path)); files.push((OutputType::Bitcode, path));
} }
save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &files); save_trans_partition(sess, &module.name, module.symbol_name_hash, &files);
}
// All codegen is finished.
unsafe {
llvm::LLVMRustDisposeTargetMachine(tm);
} }
let mut user_wants_bitcode = false; let mut user_wants_bitcode = false;
@ -858,10 +869,10 @@ pub fn run_passes(sess: &Session,
let copy_if_one_unit = |output_type: OutputType, let copy_if_one_unit = |output_type: OutputType,
keep_numbered: bool| { 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 // 1) Only one codegen unit. In this case it's no difficulty
// to copy `foo.0.x` to `foo.x`. // 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); let path = crate_output.temp_path(output_type, module_name);
copy_gracefully(&path, copy_gracefully(&path,
&crate_output.path(output_type)); &crate_output.path(output_type));
@ -962,27 +973,30 @@ pub fn run_passes(sess: &Session,
let keep_numbered_objects = needs_crate_object || let keep_numbered_objects = needs_crate_object ||
(user_wants_objects && sess.opts.cg.codegen_units > 1); (user_wants_objects && sess.opts.cg.codegen_units > 1);
for module_name in modules.iter().map(|m| Some(&m.name[..])) { for module in compiled_modules.modules.iter() {
if modules_config.emit_obj && !keep_numbered_objects { let module_name = Some(&module.name[..]);
if module.emit_obj && !keep_numbered_objects {
let path = crate_output.temp_path(OutputType::Object, module_name); let path = crate_output.temp_path(OutputType::Object, module_name);
remove(sess, &path); 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); let path = crate_output.temp_path(OutputType::Bitcode, module_name);
remove(sess, &path); 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, let path = crate_output.temp_path(OutputType::Bitcode,
Some(&metadata_module.name)); Some(&compiled_modules.metadata_module.name));
remove(sess, &path); 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, let path = crate_output.temp_path(OutputType::Bitcode,
Some(&module.name)); Some(&allocator_module.name));
remove(sess, &path); remove(sess, &path);
} }
} }
@ -1000,21 +1014,14 @@ pub fn run_passes(sess: &Session,
unsafe { llvm::LLVMRustPrintPassTimings(); } unsafe { llvm::LLVMRustPrintPassTimings(); }
} }
*trans.result.borrow_mut() = Some( *trans.result.borrow_mut() = Some(compiled_modules);
RunLLVMPassesResult {
modules,
metadata_module,
allocator_module,
}
);
} }
pub fn dump_incremental_data(trans: &CrateTranslation) { pub fn dump_incremental_data(trans: &CrateTranslation) {
let mut reuse = 0; let mut reuse = 0;
for mtrans in trans.modules.iter() { for mtrans in trans.modules.iter() {
match mtrans.source { if mtrans.pre_existing {
ModuleSource::Preexisting(..) => reuse += 1, reuse += 1;
ModuleSource::Translated(..) => (),
} }
} }
eprintln!("incremental: re-using {} out of {} modules", reuse, trans.modules.len()); 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, fn build_work_item(mtrans: ModuleTranslation,
mtrans: ModuleTranslation,
config: ModuleConfig, config: ModuleConfig,
output_names: OutputFilenames) output_names: OutputFilenames)
-> WorkItem -> WorkItem
{ {
let mut config = config;
config.tm = create_target_machine(sess);
WorkItem { WorkItem {
mtrans: mtrans, mtrans: mtrans,
config: config, config: config,
@ -1048,54 +1052,65 @@ fn build_work_item(sess: &Session,
} }
fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
-> Result<(), FatalError> -> Result<CompiledModule, FatalError>
{ {
let diag_handler = cgcx.create_diag_handler(); let diag_handler = cgcx.create_diag_handler();
unsafe { let module_name = work_item.mtrans.name.clone();
match work_item.mtrans.source {
ModuleSource::Translated(mllvm) => { let pre_existing = match work_item.mtrans.source {
debug!("llvm-optimizing {:?}", work_item.mtrans.name); ModuleSource::Translated(_) => None,
optimize_and_codegen(cgcx, ModuleSource::Preexisting(ref wp) => Some(wp.clone()),
&diag_handler, };
work_item.mtrans,
mllvm, if let Some(wp) = pre_existing {
work_item.config, let incr_comp_session_dir = cgcx.incr_comp_session_dir
work_item.output_names)?; .as_ref()
} .unwrap();
ModuleSource::Preexisting(wp) => { let name = &work_item.mtrans.name;
let incr_comp_session_dir = cgcx.incr_comp_session_dir for (kind, saved_file) in wp.saved_files {
.as_ref() let obj_out = work_item.output_names.temp_path(kind, Some(name));
.unwrap(); let source_file = in_incr_comp_dir(&incr_comp_session_dir,
let name = &work_item.mtrans.name; &saved_file);
for (kind, saved_file) in wp.saved_files { debug!("copying pre-existing module `{}` from {:?} to {}",
let obj_out = work_item.output_names.temp_path(kind, Some(name)); work_item.mtrans.name,
let source_file = in_incr_comp_dir(&incr_comp_session_dir, source_file,
&saved_file); obj_out.display());
debug!("copying pre-existing module `{}` from {:?} to {}", match link_or_copy(&source_file, &obj_out) {
work_item.mtrans.name, Ok(_) => { }
source_file, Err(err) => {
obj_out.display()); diag_handler.err(&format!("unable to copy {} to {}: {}",
match link_or_copy(&source_file, &obj_out) { source_file.display(),
Ok(_) => { } obj_out.display(),
Err(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)] #[derive(Debug)]
pub enum Message { pub enum Message {
Token(io::Result<Acquired>), Token(io::Result<Acquired>),
Done { success: bool }, Done { result: Result<CompiledModule, ()> },
WorkItem(WorkItem), WorkItem(WorkItem),
CheckErrorMessages, CheckErrorMessages,
} }
@ -1115,7 +1130,7 @@ fn start_executing_work(sess: &Session,
coordinator_receive: Receiver<Message>, coordinator_receive: Receiver<Message>,
jobserver: Client, jobserver: Client,
exported_symbols: Arc<ExportedSymbols>) exported_symbols: Arc<ExportedSymbols>)
-> thread::JoinHandle<()> { -> thread::JoinHandle<CompiledModules> {
// First up, convert our jobserver into a helper thread so we can use normal // 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 // 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 // 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. // the jobserver.
thread::spawn(move || { 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_left = total_work_item_count;
let mut work_items = Vec::with_capacity(total_work_item_count); let mut work_items = Vec::with_capacity(total_work_item_count);
let mut tokens = Vec::new(); let mut tokens = Vec::new();
@ -1253,7 +1272,8 @@ fn start_executing_work(sess: &Session,
} else { } else {
shared_emitter.fatal("failed to acquire jobserver token"); shared_emitter.fatal("failed to acquire jobserver token");
drop(trans_worker_send.send(Message::CheckErrorMessages)); 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 // Note that if the thread failed that means it panicked, so we
// abort immediately. // abort immediately.
Message::Done { success: true } => { Message::Done { result: Ok(compiled_module) } => {
drop(tokens.pop()); drop(tokens.pop());
running -= 1; running -= 1;
drop(trans_worker_send.send(Message::CheckErrorMessages)); 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"); shared_emitter.fatal("aborting due to worker thread panic");
drop(trans_worker_send.send(Message::CheckErrorMessages)); drop(trans_worker_send.send(Message::CheckErrorMessages));
return // Exit the coordinator thread
panic!()
} }
msg @ Message::CheckErrorMessages => { msg @ Message::CheckErrorMessages => {
bug!("unexpected message: {:?}", msg); 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. // we exit.
struct Bomb { struct Bomb {
coordinator_send: Sender<Message>, coordinator_send: Sender<Message>,
success: bool, result: Option<CompiledModule>,
} }
impl Drop for Bomb { impl Drop for Bomb {
fn drop(&mut self) { 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 { let mut bomb = Bomb {
coordinator_send: cgcx.coordinator_send.clone(), coordinator_send: cgcx.coordinator_send.clone(),
success: false, result: None,
}; };
// Execute the work itself, and if it finishes successfully then flag // 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 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 // 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. // seen by the main thread, but hey we might as well try anyway.
drop(execute_work_item(&cgcx, work).is_err()); bomb.result = Some(execute_work_item(&cgcx, work).unwrap());
bomb.success = true;
}); });
} }

View file

@ -27,6 +27,7 @@ use super::OngoingCrateTranslation;
use super::ModuleLlvm; use super::ModuleLlvm;
use super::ModuleSource; use super::ModuleSource;
use super::ModuleTranslation; use super::ModuleTranslation;
use super::ModuleKind;
use assert_module_sources; use assert_module_sources;
use back::link; use back::link;
@ -952,6 +953,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
llcx: metadata_llcx, llcx: metadata_llcx,
llmod: metadata_llmod, llmod: metadata_llmod,
}), }),
kind: ModuleKind::Metadata,
}; };
let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); 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() { !tcx.sess.opts.output_types.should_trans() {
let empty_exported_symbols = ExportedSymbols::empty(); let empty_exported_symbols = ExportedSymbols::empty();
let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols); let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols);
return OngoingCrateTranslation { let crate_translation = OngoingCrateTranslation {
crate_name: tcx.crate_name(LOCAL_CRATE), crate_name: tcx.crate_name(LOCAL_CRATE),
link: link_meta, link: link_meta,
metadata: metadata, metadata: metadata,
@ -970,12 +972,18 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
linker_info: linker_info, linker_info: linker_info,
windows_subsystem: None, windows_subsystem: None,
no_integrated_as: false, no_integrated_as: false,
result: ::std::cell::RefCell::new(Some(::back::write::RunLLVMPassesResult { result: ::std::cell::RefCell::new(None),
modules: vec![],
metadata_module: metadata_module,
allocator_module: 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, 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 { let module = ModuleTranslation {
name: cgu_name, name: cgu_name,
symbol_name_hash, symbol_name_hash,
source: ModuleSource::Preexisting(buf.clone()) source: ModuleSource::Preexisting(buf.clone()),
kind: ModuleKind::Regular,
}; };
return (Stats::default(), module); return (Stats::default(), module);
} }
@ -1108,7 +1117,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: ModuleSource::Translated(ModuleLlvm { source: ModuleSource::Translated(ModuleLlvm {
llcx: ccx.llcx(), llcx: ccx.llcx(),
llmod: ccx.llmod(), 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(), name: link::ALLOCATOR_MODULE_NAME.to_string(),
symbol_name_hash: 0, // we always rebuild allocator shims symbol_name_hash: 0, // we always rebuild allocator shims
source: ModuleSource::Translated(modules), source: ModuleSource::Translated(modules),
kind: ModuleKind::Allocator,
}) })
} }
}); });

View file

@ -135,7 +135,6 @@ mod type_;
mod type_of; mod type_of;
mod value; mod value;
#[derive(Clone)]
pub struct ModuleTranslation { pub struct ModuleTranslation {
/// The name of the module. When the crate may be saved between /// The name of the module. When the crate may be saved between
/// compilations, incremental compilation requires that name be /// compilations, incremental compilation requires that name be
@ -145,6 +144,58 @@ pub struct ModuleTranslation {
pub name: String, pub name: String,
pub symbol_name_hash: u64, pub symbol_name_hash: u64,
pub source: ModuleSource, 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)] #[derive(Clone)]
@ -156,7 +207,7 @@ pub enum ModuleSource {
Translated(ModuleLlvm), Translated(ModuleLlvm),
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone, Debug)]
pub struct ModuleLlvm { pub struct ModuleLlvm {
pub llcx: llvm::ContextRef, pub llcx: llvm::ContextRef,
pub llmod: llvm::ModuleRef, pub llmod: llvm::ModuleRef,
@ -167,9 +218,9 @@ unsafe impl Sync for ModuleTranslation { }
pub struct CrateTranslation { pub struct CrateTranslation {
pub crate_name: Symbol, pub crate_name: Symbol,
pub modules: Vec<ModuleTranslation>, pub modules: Vec<CompiledModule>,
pub metadata_module: ModuleTranslation, pub metadata_module: CompiledModule,
pub allocator_module: Option<ModuleTranslation>, pub allocator_module: Option<CompiledModule>,
pub link: rustc::middle::cstore::LinkMeta, pub link: rustc::middle::cstore::LinkMeta,
pub metadata: rustc::middle::cstore::EncodedMetadata, pub metadata: rustc::middle::cstore::EncodedMetadata,
pub exported_symbols: Arc<back::symbol_export::ExportedSymbols>, pub exported_symbols: Arc<back::symbol_export::ExportedSymbols>,
@ -189,7 +240,7 @@ pub struct OngoingCrateTranslation {
pub no_integrated_as: bool, pub no_integrated_as: bool,
// This will be replaced by a Future. // 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 { impl OngoingCrateTranslation {