Rollup merge of #41287 - nikomatsakis:incr-comp-refactor-trans, r=eddyb

Miscellneous refactorings of trans

This doesn't achieve any particular goal yet, but it's a collection of refactorings with the common goal of turning `SharedCrateContext` etc into stuff that we can use with on-demand and actually expect to hash in a stable fashion for incremental. Not there yet, clearly.

r? @eddyb
cc @michaelwoerister
This commit is contained in:
Corey Farwell 2017-04-13 22:01:27 -04:00 committed by GitHub
commit adc2b10399
15 changed files with 233 additions and 347 deletions

View File

@ -53,7 +53,6 @@ pub use self::NativeLibraryKind::*;
#[derive(Clone, Debug)]
pub struct LinkMeta {
pub crate_name: Symbol,
pub crate_hash: Svh,
}

View File

@ -13,7 +13,6 @@ pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
use dep_graph::DepGraph;
use hir::def_id::{CrateNum, DefIndex};
use hir::svh::Svh;
use lint;
use middle::cstore::CrateStore;
use middle::dependency_format;
@ -402,15 +401,14 @@ impl Session {
/// Returns the symbol name for the registrar function,
/// given the crate Svh and the function DefIndex.
pub fn generate_plugin_registrar_symbol(&self, svh: &Svh, index: DefIndex)
pub fn generate_plugin_registrar_symbol(&self, disambiguator: Symbol, index: DefIndex)
-> String {
format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize())
format!("__rustc_plugin_registrar__{}_{}", disambiguator, index.as_usize())
}
pub fn generate_derive_registrar_symbol(&self,
svh: &Svh,
index: DefIndex) -> String {
format!("__rustc_derive_registrar__{}_{}", svh, index.as_usize())
pub fn generate_derive_registrar_symbol(&self, disambiguator: Symbol, index: DefIndex)
-> String {
format!("__rustc_derive_registrar__{}_{}", disambiguator, index.as_usize())
}
pub fn sysroot<'a>(&'a self) -> &'a Path {

View File

@ -1140,7 +1140,7 @@ pub fn phase_6_link_output(sess: &Session,
outputs: &OutputFilenames) {
time(sess.time_passes(),
"linking",
|| link::link_binary(sess, trans, outputs, &trans.link.crate_name.as_str()));
|| link::link_binary(sess, trans, outputs, &trans.crate_name.as_str()));
}
fn escape_dep_filename(filename: &str) -> String {

View File

@ -600,7 +600,7 @@ impl<'a> CrateLoader<'a> {
Err(err) => self.sess.span_fatal(span, &err),
};
let sym = self.sess.generate_derive_registrar_symbol(&root.hash,
let sym = self.sess.generate_derive_registrar_symbol(root.disambiguator,
root.macro_derive_registrar.unwrap());
let registrar = unsafe {
let sym = match lib.symbol(&sym) {
@ -654,7 +654,7 @@ impl<'a> CrateLoader<'a> {
/// Look for a plugin registrar. Returns library path, crate
/// SVH and DefIndex of the registrar function.
pub fn find_plugin_registrar(&mut self, span: Span, name: &str)
-> Option<(PathBuf, Svh, DefIndex)> {
-> Option<(PathBuf, Symbol, DefIndex)> {
let ekrate = self.read_extension_crate(span, &ExternCrateInfo {
name: Symbol::intern(name),
ident: Symbol::intern(name),
@ -675,7 +675,7 @@ impl<'a> CrateLoader<'a> {
let root = ekrate.metadata.get_root();
match (ekrate.dylib.as_ref(), root.plugin_registrar_fn) {
(Some(dylib), Some(reg)) => {
Some((dylib.to_path_buf(), root.hash, reg))
Some((dylib.to_path_buf(), root.disambiguator, reg))
}
(None, Some(_)) => {
span_err!(self.sess, span, E0457,

View File

@ -14,7 +14,7 @@ use schema::*;
use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary,
EncodedMetadata, EncodedMetadataHash};
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE};
use rustc::hir::map::definitions::DefPathTable;
use rustc::middle::dependency_format::Linkage;
use rustc::middle::lang_items;
@ -1380,7 +1380,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let link_meta = self.link_meta;
let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro);
let root = self.lazy(&CrateRoot {
name: link_meta.crate_name,
name: tcx.crate_name(LOCAL_CRATE),
triple: tcx.sess.opts.target_triple.clone(),
hash: link_meta.crate_hash,
disambiguator: tcx.sess.local_crate_disambiguator(),

View File

@ -100,8 +100,8 @@ impl<'a> PluginLoader<'a> {
fn load_plugin(&mut self, span: Span, name: &str, args: Vec<ast::NestedMetaItem>) {
let registrar = self.reader.find_plugin_registrar(span, name);
if let Some((lib, svh, index)) = registrar {
let symbol = self.sess.generate_plugin_registrar_symbol(&svh, index);
if let Some((lib, disambiguator, index)) = registrar {
let symbol = self.sess.generate_plugin_registrar_symbol(disambiguator, index);
let fun = self.dylink_registrar(span, lib, symbol);
self.plugins.push(PluginRegistrar {
fun: fun,

View File

@ -47,7 +47,6 @@ use std::str;
use flate;
use syntax::ast;
use syntax::attr;
use syntax::symbol::Symbol;
use syntax_pos::Span;
/// The LLVM module name containing crate-metadata. This includes a `.` on
@ -136,11 +135,8 @@ pub fn find_crate_name(sess: Option<&Session>,
"rust_out".to_string()
}
pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap,
name: &str)
-> LinkMeta {
pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap) -> LinkMeta {
let r = LinkMeta {
crate_name: Symbol::intern(name),
crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate].to_smaller_hash()),
};
info!("{:?}", r);

View File

@ -15,6 +15,7 @@ use back::symbol_names::symbol_name;
use util::nodemap::FxHashMap;
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use rustc::session::config;
use rustc::ty::TyCtxt;
use syntax::attr;
use trans_item::TransItem;
@ -64,15 +65,15 @@ impl ExportedSymbols {
}
if let Some(id) = scx.sess().derive_registrar_fn.get() {
let svh = &scx.link_meta().crate_hash;
let def_id = scx.tcx().hir.local_def_id(id);
let idx = def_id.index;
let registrar = scx.sess().generate_derive_registrar_symbol(svh, idx);
let disambiguator = scx.sess().local_crate_disambiguator();
let registrar = scx.sess().generate_derive_registrar_symbol(disambiguator, idx);
local_crate.push((registrar, SymbolExportLevel::C));
}
if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) {
local_crate.push((scx.metadata_symbol_name(),
local_crate.push((metadata_symbol_name(scx.tcx()),
SymbolExportLevel::Rust));
}
@ -173,6 +174,12 @@ impl ExportedSymbols {
}
}
pub fn metadata_symbol_name(tcx: TyCtxt) -> String {
format!("rust_metadata_{}_{}",
tcx.crate_name(LOCAL_CRATE),
tcx.crate_disambiguator(LOCAL_CRATE))
}
pub fn crate_export_threshold(crate_type: config::CrateType)
-> SymbolExportLevel {
match crate_type {

View File

@ -179,14 +179,14 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
if let Some(id) = node_id {
if scx.sess().plugin_registrar_fn.get() == Some(id) {
let svh = &scx.link_meta().crate_hash;
let idx = def_id.index;
return scx.sess().generate_plugin_registrar_symbol(svh, idx);
let disambiguator = scx.sess().local_crate_disambiguator();
return scx.sess().generate_plugin_registrar_symbol(disambiguator, idx);
}
if scx.sess().derive_registrar_fn.get() == Some(id) {
let svh = &scx.link_meta().crate_hash;
let idx = def_id.index;
return scx.sess().generate_derive_registrar_symbol(svh, idx);
let disambiguator = scx.sess().local_crate_disambiguator();
return scx.sess().generate_derive_registrar_symbol(disambiguator, idx);
}
}

View File

@ -32,13 +32,14 @@ use assert_module_sources;
use back::link;
use back::linker::LinkerInfo;
use back::symbol_export::{self, ExportedSymbols};
use llvm::{Linkage, ValueRef, Vector, get_param};
use llvm::{ContextRef, Linkage, ModuleRef, ValueRef, Vector, get_param};
use llvm;
use rustc::hir::def_id::LOCAL_CRATE;
use middle::lang_items::StartFnLangItem;
use middle::cstore::EncodedMetadata;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct};
use rustc::dep_graph::{AssertDepGraphSafe, DepNode};
use rustc::middle::cstore::LinkMeta;
use rustc::hir::map as hir_map;
use rustc::util::common::time;
use session::config::{self, NoDebugInfo};
@ -56,7 +57,7 @@ use common::CrateContext;
use common::{type_is_zero_size, val_ty};
use common;
use consts;
use context::{SharedCrateContext, CrateContextList};
use context::{self, LocalCrateContext, SharedCrateContext, Stats};
use debuginfo;
use declare;
use machine;
@ -724,11 +725,16 @@ fn contains_null(s: &str) -> bool {
s.bytes().any(|b| b == 0)
}
fn write_metadata(cx: &SharedCrateContext,
exported_symbols: &NodeSet)
-> EncodedMetadata {
fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
link_meta: &LinkMeta,
exported_symbols: &NodeSet)
-> (ContextRef, ModuleRef, EncodedMetadata) {
use flate;
let (metadata_llcx, metadata_llmod) = unsafe {
context::create_context_and_module(tcx.sess, "metadata")
};
#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum MetadataKind {
None,
@ -736,7 +742,7 @@ fn write_metadata(cx: &SharedCrateContext,
Compressed
}
let kind = cx.sess().crate_types.borrow().iter().map(|ty| {
let kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
match *ty {
config::CrateTypeExecutable |
config::CrateTypeStaticlib |
@ -750,35 +756,35 @@ fn write_metadata(cx: &SharedCrateContext,
}).max().unwrap();
if kind == MetadataKind::None {
return EncodedMetadata {
return (metadata_llcx, metadata_llmod, EncodedMetadata {
raw_data: vec![],
hashes: vec![],
};
});
}
let cstore = &cx.tcx().sess.cstore;
let metadata = cstore.encode_metadata(cx.tcx(),
cx.link_meta(),
let cstore = &tcx.sess.cstore;
let metadata = cstore.encode_metadata(tcx,
&link_meta,
exported_symbols);
if kind == MetadataKind::Uncompressed {
return metadata;
return (metadata_llcx, metadata_llmod, metadata);
}
assert!(kind == MetadataKind::Compressed);
let mut compressed = cstore.metadata_encoding_version().to_vec();
compressed.extend_from_slice(&flate::deflate_bytes(&metadata.raw_data));
let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed);
let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false);
let name = cx.metadata_symbol_name();
let llmeta = C_bytes_in_context(metadata_llcx, &compressed);
let llconst = C_struct_in_context(metadata_llcx, &[llmeta], false);
let name = symbol_export::metadata_symbol_name(tcx);
let buf = CString::new(name).unwrap();
let llglobal = unsafe {
llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf.as_ptr())
llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst).to_ref(), buf.as_ptr())
};
unsafe {
llvm::LLVMSetInitializer(llglobal, llconst);
let section_name =
cx.tcx().sess.cstore.metadata_section_name(&cx.sess().target.target);
tcx.sess.cstore.metadata_section_name(&tcx.sess.target.target);
let name = CString::new(section_name).unwrap();
llvm::LLVMSetSection(llglobal, name.as_ptr());
@ -787,15 +793,16 @@ fn write_metadata(cx: &SharedCrateContext,
// metadata doesn't get loaded into memory.
let directive = format!(".section {}", section_name);
let directive = CString::new(directive).unwrap();
llvm::LLVMSetModuleInlineAsm(cx.metadata_llmod(), directive.as_ptr())
llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr())
}
return metadata;
return (metadata_llcx, metadata_llmod, metadata);
}
/// Find any symbols that are defined in one compilation unit, but not declared
/// in any other compilation unit. Give these symbols internal linkage.
fn internalize_symbols<'a, 'tcx>(sess: &Session,
ccxs: &CrateContextList<'a, 'tcx>,
scx: &SharedCrateContext<'a, 'tcx>,
llvm_modules: &[ModuleLlvm],
symbol_map: &SymbolMap<'tcx>,
exported_symbols: &ExportedSymbols) {
let export_threshold =
@ -810,7 +817,6 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
.map(|&(ref name, _)| &name[..])
.collect::<FxHashSet<&str>>();
let scx = ccxs.shared();
let tcx = scx.tcx();
let incr_comp = sess.opts.debugging_opts.incremental.is_some();
@ -825,8 +831,8 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
// incremental compilation, we don't need to collect. See below for more
// information.
if !incr_comp {
for ccx in ccxs.iter_need_trans() {
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
for ll in llvm_modules {
for val in iter_globals(ll.llmod).chain(iter_functions(ll.llmod)) {
let linkage = llvm::LLVMRustGetLinkage(val);
// We only care about external declarations (not definitions)
// and available_externally definitions.
@ -862,8 +868,8 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
// Examine each external definition. If the definition is not used in
// any other compilation unit, and is not reachable from other crates,
// then give it internal linkage.
for ccx in ccxs.iter_need_trans() {
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
for ll in llvm_modules {
for val in iter_globals(ll.llmod).chain(iter_functions(ll.llmod)) {
let linkage = llvm::LLVMRustGetLinkage(val);
let is_externally_visible = (linkage == llvm::Linkage::ExternalLinkage) ||
@ -922,19 +928,20 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
// when using MSVC linker. We do this only for data, as linker can fix up
// code references on its own.
// See #26591, #27438
fn create_imps(cx: &CrateContextList) {
fn create_imps(sess: &Session,
llvm_modules: &[ModuleLlvm]) {
// The x86 ABI seems to require that leading underscores are added to symbol
// names, so we need an extra underscore on 32-bit. There's also a leading
// '\x01' here which disables LLVM's symbol mangling (e.g. no extra
// underscores added in front).
let prefix = if cx.shared().sess().target.target.target_pointer_width == "32" {
let prefix = if sess.target.target.target_pointer_width == "32" {
"\x01__imp__"
} else {
"\x01__imp_"
};
unsafe {
for ccx in cx.iter_need_trans() {
let exported: Vec<_> = iter_globals(ccx.llmod())
for ll in llvm_modules {
let exported: Vec<_> = iter_globals(ll.llmod)
.filter(|&val| {
llvm::LLVMRustGetLinkage(val) ==
llvm::Linkage::ExternalLinkage &&
@ -942,13 +949,13 @@ fn create_imps(cx: &CrateContextList) {
})
.collect();
let i8p_ty = Type::i8p(&ccx);
let i8p_ty = Type::i8p_llcx(ll.llcx);
for val in exported {
let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
let mut imp_name = prefix.as_bytes().to_vec();
imp_name.extend(name.to_bytes());
let imp_name = CString::new(imp_name).unwrap();
let imp = llvm::LLVMAddGlobal(ccx.llmod(),
let imp = llvm::LLVMAddGlobal(ll.llmod,
i8p_ty.to_ref(),
imp_name.as_ptr() as *const _);
let init = llvm::LLVMConstBitCast(val, i8p_ty.to_ref());
@ -1058,28 +1065,28 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// particular items that will be processed.
let krate = tcx.hir.krate();
let ty::CrateAnalysis { reachable, name, .. } = analysis;
let ty::CrateAnalysis { reachable, .. } = analysis;
let exported_symbols = find_exported_symbols(tcx, reachable);
let check_overflow = tcx.sess.overflow_checks();
let link_meta = link::build_link_meta(incremental_hashes_map, &name);
let link_meta = link::build_link_meta(incremental_hashes_map);
let shared_ccx = SharedCrateContext::new(tcx,
link_meta.clone(),
exported_symbols,
check_overflow);
// Translate the metadata.
let metadata = time(tcx.sess.time_passes(), "write metadata", || {
write_metadata(&shared_ccx, shared_ccx.exported_symbols())
});
let (metadata_llcx, metadata_llmod, metadata) =
time(tcx.sess.time_passes(), "write metadata", || {
write_metadata(tcx, &link_meta, shared_ccx.exported_symbols())
});
let metadata_module = ModuleTranslation {
name: link::METADATA_MODULE_NAME.to_string(),
symbol_name_hash: 0, // we always rebuild metadata, at least for now
source: ModuleSource::Translated(ModuleLlvm {
llcx: shared_ccx.metadata_llcx(),
llmod: shared_ccx.metadata_llmod(),
llcx: metadata_llcx,
llmod: metadata_llmod,
}),
};
let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
@ -1090,6 +1097,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let empty_exported_symbols = ExportedSymbols::empty();
let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols);
return CrateTranslation {
crate_name: tcx.crate_name(LOCAL_CRATE),
modules: vec![],
metadata_module: metadata_module,
link: link_meta,
@ -1107,73 +1115,78 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let symbol_map = Rc::new(symbol_map);
let previous_work_products = trans_reuse_previous_work_products(&shared_ccx,
&codegen_units,
&symbol_map);
let crate_context_list = CrateContextList::new(&shared_ccx,
codegen_units,
previous_work_products,
symbol_map.clone());
let modules: Vec<_> = crate_context_list.iter_all()
.map(|ccx| {
let source = match ccx.previous_work_product() {
Some(buf) => ModuleSource::Preexisting(buf.clone()),
None => ModuleSource::Translated(ModuleLlvm {
llcx: ccx.llcx(),
llmod: ccx.llmod(),
}),
};
ModuleTranslation {
name: String::from(ccx.codegen_unit().name()),
symbol_name_hash: ccx.codegen_unit()
.compute_symbol_name_hash(&shared_ccx,
&symbol_map),
source: source,
}
let mut all_stats = Stats::default();
let modules: Vec<ModuleTranslation> = codegen_units
.into_iter()
.map(|cgu| {
let dep_node = cgu.work_product_dep_node();
let (stats, module) =
tcx.dep_graph.with_task(dep_node,
AssertDepGraphSafe(&shared_ccx),
AssertDepGraphSafe((cgu, symbol_map.clone())),
module_translation);
all_stats.extend(stats);
module
})
.collect();
assert_module_sources::assert_module_sources(tcx, &modules);
fn module_translation<'a, 'tcx>(
scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>,
args: AssertDepGraphSafe<(CodegenUnit<'tcx>, Rc<SymbolMap<'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, symbol_map)) = args;
// Instantiate translation items without filling out definitions yet...
for ccx in crate_context_list.iter_need_trans() {
let dep_node = ccx.codegen_unit().work_product_dep_node();
tcx.dep_graph.with_task(dep_node,
ccx,
AssertDepGraphSafe(symbol_map.clone()),
trans_decl_task);
let cgu_name = String::from(cgu.name());
let cgu_id = cgu.work_product_id();
let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_map);
fn trans_decl_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>,
symbol_map: AssertDepGraphSafe<Rc<SymbolMap<'tcx>>>) {
// FIXME(#40304): Instead of this, the symbol-map should be an
// on-demand thing that we compute.
let AssertDepGraphSafe(symbol_map) = symbol_map;
let cgu = ccx.codegen_unit();
let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map);
for (trans_item, linkage) in trans_items {
// 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 {
println!("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())
};
return (Stats::default(), module);
}
// Instantiate translation items without filling out definitions yet...
let lcx = LocalCrateContext::new(scx, cgu, symbol_map.clone());
let module = {
let ccx = CrateContext::new(scx, &lcx);
let trans_items = ccx.codegen_unit()
.items_in_deterministic_order(ccx.tcx(), &symbol_map);
for &(trans_item, linkage) in &trans_items {
trans_item.predefine(&ccx, linkage);
}
}
}
// ... and now that we have everything pre-defined, fill out those definitions.
for ccx in crate_context_list.iter_need_trans() {
let dep_node = ccx.codegen_unit().work_product_dep_node();
tcx.dep_graph.with_task(dep_node,
ccx,
AssertDepGraphSafe(symbol_map.clone()),
trans_def_task);
fn trans_def_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>,
symbol_map: AssertDepGraphSafe<Rc<SymbolMap<'tcx>>>) {
// FIXME(#40304): Instead of this, the symbol-map should be an
// on-demand thing that we compute.
let AssertDepGraphSafe(symbol_map) = symbol_map;
let cgu = ccx.codegen_unit();
let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map);
for (trans_item, _) in trans_items {
// ... and now that we have everything pre-defined, fill out those definitions.
for &(trans_item, _) in &trans_items {
trans_item.define(&ccx);
}
@ -1211,26 +1224,38 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if ccx.sess().opts.debuginfo != NoDebugInfo {
debuginfo::finalize(&ccx);
}
}
ModuleTranslation {
name: cgu_name,
symbol_name_hash,
source: ModuleSource::Translated(ModuleLlvm {
llcx: ccx.llcx(),
llmod: ccx.llmod(),
})
}
};
(lcx.into_stats(), module)
}
assert_module_sources::assert_module_sources(tcx, &modules);
symbol_names_test::report_symbol_names(&shared_ccx);
if shared_ccx.sess().trans_stats() {
let stats = shared_ccx.stats();
println!("--- trans stats ---");
println!("n_glues_created: {}", stats.n_glues_created.get());
println!("n_null_glues: {}", stats.n_null_glues.get());
println!("n_real_glues: {}", stats.n_real_glues.get());
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_fns: {}", stats.n_fns.get());
println!("n_inlines: {}", stats.n_inlines.get());
println!("n_closures: {}", stats.n_closures.get());
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!("fn stats:");
stats.fn_stats.borrow_mut().sort_by(|&(_, insns_a), &(_, insns_b)| {
all_stats.fn_stats.borrow_mut().sort_by(|&(_, insns_a), &(_, insns_b)| {
insns_b.cmp(&insns_a)
});
for tuple in stats.fn_stats.borrow().iter() {
for tuple in all_stats.fn_stats.borrow().iter() {
match *tuple {
(ref name, insns) => {
println!("{} insns, {}", insns, *name);
@ -1240,7 +1265,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
if shared_ccx.sess().count_llvm_insns() {
for (k, v) in shared_ccx.stats().llvm_insns.borrow().iter() {
for (k, v) in all_stats.llvm_insns.borrow().iter() {
println!("{:7} {}", *v, *k);
}
}
@ -1250,11 +1275,23 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let exported_symbols = ExportedSymbols::compute_from(&shared_ccx,
&symbol_map);
// Get the list of llvm modules we created. We'll do a few wacky
// transforms on them now.
let llvm_modules: Vec<_> =
modules.iter()
.filter_map(|module| match module.source {
ModuleSource::Translated(llvm) => Some(llvm),
_ => None,
})
.collect();
// Now that we have all symbols that are exported from the CGUs of this
// crate, we can run the `internalize_symbols` pass.
time(shared_ccx.sess().time_passes(), "internalize symbols", || {
internalize_symbols(sess,
&crate_context_list,
&shared_ccx,
&llvm_modules,
&symbol_map,
&exported_symbols);
});
@ -1265,7 +1302,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if sess.target.target.options.is_like_msvc &&
sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
create_imps(&crate_context_list);
create_imps(sess, &llvm_modules);
}
let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols);
@ -1282,6 +1319,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
});
CrateTranslation {
crate_name: tcx.crate_name(LOCAL_CRATE),
modules: modules,
metadata_module: metadata_module,
link: link_meta,
@ -1480,43 +1518,6 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
}
}
/// For each CGU, identify if we can reuse an existing object file (or
/// maybe other context).
fn trans_reuse_previous_work_products(scx: &SharedCrateContext,
codegen_units: &[CodegenUnit],
symbol_map: &SymbolMap)
-> Vec<Option<WorkProduct>> {
debug!("trans_reuse_previous_work_products()");
codegen_units
.iter()
.map(|cgu| {
let id = cgu.work_product_id();
let hash = cgu.compute_symbol_name_hash(scx, symbol_map);
debug!("trans_reuse_previous_work_products: id={:?} hash={}", id, hash);
if let Some(work_product) = scx.dep_graph().previous_work_product(&id) {
if work_product.input_hash == hash {
debug!("trans_reuse_previous_work_products: reusing {:?}", work_product);
return Some(work_product);
} else {
if scx.sess().opts.debugging_opts.incremental_info {
println!("incremental: CGU `{}` invalidated because of \
changed partitioning hash.",
cgu.name());
}
debug!("trans_reuse_previous_work_products: \
not reusing {:?} because hash changed to {:?}",
work_product, hash);
}
}
None
})
.collect()
}
fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>)
-> (Vec<CodegenUnit<'tcx>>, SymbolMap<'tcx>) {
let time_passes = scx.sess().time_passes();

View File

@ -10,9 +10,7 @@
use llvm;
use llvm::{ContextRef, ModuleRef, ValueRef};
use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap,
DepTrackingMapConfig, WorkProduct};
use middle::cstore::LinkMeta;
use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::traits;
@ -47,6 +45,7 @@ use syntax::symbol::InternedString;
use syntax_pos::DUMMY_SP;
use abi::Abi;
#[derive(Clone, Default)]
pub struct Stats {
pub n_glues_created: Cell<usize>,
pub n_null_glues: Cell<usize>,
@ -60,19 +59,30 @@ pub struct Stats {
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
/// (aside from metadata-related ones).
pub struct SharedCrateContext<'a, 'tcx: 'a> {
metadata_llmod: ModuleRef,
metadata_llcx: ContextRef,
exported_symbols: NodeSet,
link_meta: LinkMeta,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
empty_param_env: ty::ParameterEnvironment<'tcx>,
stats: Stats,
check_overflow: bool,
use_dll_storage_attrs: bool,
@ -89,7 +99,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
pub struct LocalCrateContext<'tcx> {
llmod: ModuleRef,
llcx: ContextRef,
previous_work_product: Option<WorkProduct>,
stats: Stats,
codegen_unit: CodegenUnit<'tcx>,
needs_unwind_cleanup_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
/// Cache instances of monomorphic and polymorphic items
@ -214,109 +224,25 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
}
}
/// This list owns a number of LocalCrateContexts and binds them to their common
/// SharedCrateContext. This type just exists as a convenience, something to
/// pass around all LocalCrateContexts with and get an iterator over them.
pub struct CrateContextList<'a, 'tcx: 'a> {
shared: &'a SharedCrateContext<'a, 'tcx>,
local_ccxs: Vec<LocalCrateContext<'tcx>>,
}
impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> {
pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>,
codegen_units: Vec<CodegenUnit<'tcx>>,
previous_work_products: Vec<Option<WorkProduct>>,
symbol_map: Rc<SymbolMap<'tcx>>)
-> CrateContextList<'a, 'tcx> {
CrateContextList {
shared: shared_ccx,
local_ccxs: codegen_units.into_iter().zip(previous_work_products).map(|(cgu, wp)| {
LocalCrateContext::new(shared_ccx, cgu, wp, symbol_map.clone())
}).collect()
}
}
/// Iterate over all crate contexts, whether or not they need
/// translation. That is, whether or not a `.o` file is available
/// for re-use from a previous incr. comp.).
pub fn iter_all<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> {
CrateContextIterator {
shared: self.shared,
index: 0,
local_ccxs: &self.local_ccxs[..],
filter_to_previous_work_product_unavail: false,
}
}
/// Iterator over all CCX that need translation (cannot reuse results from
/// previous incr. comp.).
pub fn iter_need_trans<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> {
CrateContextIterator {
shared: self.shared,
index: 0,
local_ccxs: &self.local_ccxs[..],
filter_to_previous_work_product_unavail: true,
}
}
pub fn shared(&self) -> &'a SharedCrateContext<'a, 'tcx> {
self.shared
}
}
/// A CrateContext value binds together one LocalCrateContext with the
/// SharedCrateContext. It exists as a convenience wrapper, so we don't have to
/// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans.
pub struct CrateContext<'a, 'tcx: 'a> {
shared: &'a SharedCrateContext<'a, 'tcx>,
local_ccxs: &'a [LocalCrateContext<'tcx>],
/// The index of `local` in `local_ccxs`. This is used in
/// `maybe_iter(true)` to identify the original `LocalCrateContext`.
index: usize,
local_ccx: &'a LocalCrateContext<'tcx>,
}
impl<'a, 'tcx> CrateContext<'a, 'tcx> {
pub fn new(shared: &'a SharedCrateContext<'a, 'tcx>,
local_ccx: &'a LocalCrateContext<'tcx>)
-> Self {
CrateContext { shared, local_ccx }
}
}
impl<'a, 'tcx> DepGraphSafe for CrateContext<'a, 'tcx> {
}
pub struct CrateContextIterator<'a, 'tcx: 'a> {
shared: &'a SharedCrateContext<'a, 'tcx>,
local_ccxs: &'a [LocalCrateContext<'tcx>],
index: usize,
/// if true, only return results where `previous_work_product` is none
filter_to_previous_work_product_unavail: bool,
}
impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> {
type Item = CrateContext<'a, 'tcx>;
fn next(&mut self) -> Option<CrateContext<'a, 'tcx>> {
loop {
if self.index >= self.local_ccxs.len() {
return None;
}
let index = self.index;
self.index += 1;
let ccx = CrateContext {
shared: self.shared,
index: index,
local_ccxs: self.local_ccxs,
};
if
self.filter_to_previous_work_product_unavail &&
ccx.previous_work_product().is_some()
{
continue;
}
return Some(ccx);
}
}
}
pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode {
let reloc_model_arg = match sess.opts.cg.relocation_model {
Some(ref s) => &s[..],
@ -347,7 +273,7 @@ pub fn is_pie_binary(sess: &Session) -> bool {
!is_any_library(sess) && get_reloc_model(sess) == llvm::RelocMode::PIC
}
unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) {
pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) {
let llcx = llvm::LLVMContextCreate();
let mod_name = CString::new(mod_name).unwrap();
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
@ -405,14 +331,9 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR
impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
link_meta: LinkMeta,
exported_symbols: NodeSet,
check_overflow: bool)
-> SharedCrateContext<'b, 'tcx> {
let (metadata_llcx, metadata_llmod) = unsafe {
create_context_and_module(&tcx.sess, "metadata")
};
// 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
@ -459,23 +380,9 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc;
SharedCrateContext {
metadata_llmod: metadata_llmod,
metadata_llcx: metadata_llcx,
exported_symbols: exported_symbols,
link_meta: link_meta,
empty_param_env: tcx.empty_parameter_environment(),
tcx: tcx,
stats: Stats {
n_glues_created: Cell::new(0),
n_null_glues: Cell::new(0),
n_real_glues: Cell::new(0),
n_fns: Cell::new(0),
n_inlines: Cell::new(0),
n_closures: Cell::new(0),
n_llvm_insns: Cell::new(0),
llvm_insns: RefCell::new(FxHashMap()),
fn_stats: RefCell::new(Vec::new()),
},
check_overflow: check_overflow,
use_dll_storage_attrs: use_dll_storage_attrs,
translation_items: RefCell::new(FxHashSet()),
@ -492,14 +399,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
ty.is_sized(self.tcx, &self.empty_param_env, DUMMY_SP)
}
pub fn metadata_llmod(&self) -> ModuleRef {
self.metadata_llmod
}
pub fn metadata_llcx(&self) -> ContextRef {
self.metadata_llcx
}
pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet {
&self.exported_symbols
}
@ -512,10 +411,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
&self.project_cache
}
pub fn link_meta<'a>(&'a self) -> &'a LinkMeta {
&self.link_meta
}
pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
self.tcx
}
@ -528,10 +423,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
&self.tcx.dep_graph
}
pub fn stats<'a>(&'a self) -> &'a Stats {
&self.stats
}
pub fn use_dll_storage_attrs(&self) -> bool {
self.use_dll_storage_attrs
}
@ -539,20 +430,13 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
pub fn translation_items(&self) -> &RefCell<FxHashSet<TransItem<'tcx>>> {
&self.translation_items
}
pub fn metadata_symbol_name(&self) -> String {
format!("rust_metadata_{}_{}",
self.link_meta().crate_name,
self.link_meta().crate_hash)
}
}
impl<'tcx> LocalCrateContext<'tcx> {
fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
codegen_unit: CodegenUnit<'tcx>,
previous_work_product: Option<WorkProduct>,
symbol_map: Rc<SymbolMap<'tcx>>)
-> LocalCrateContext<'tcx> {
pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
codegen_unit: CodegenUnit<'tcx>,
symbol_map: Rc<SymbolMap<'tcx>>)
-> LocalCrateContext<'tcx> {
unsafe {
// Append ".rs" to LLVM module identifier.
//
@ -578,7 +462,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
let local_ccx = LocalCrateContext {
llmod: llmod,
llcx: llcx,
previous_work_product: previous_work_product,
stats: Stats::default(),
codegen_unit: codegen_unit,
needs_unwind_cleanup_cache: RefCell::new(FxHashMap()),
instances: RefCell::new(FxHashMap()),
@ -647,10 +531,13 @@ impl<'tcx> LocalCrateContext<'tcx> {
assert!(local_ccxs.len() == 1);
CrateContext {
shared: shared,
index: 0,
local_ccxs: local_ccxs
local_ccx: &local_ccxs[0]
}
}
pub fn into_stats(self) -> Stats {
self.stats
}
}
impl<'b, 'tcx> CrateContext<'b, 'tcx> {
@ -659,7 +546,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
}
fn local(&self) -> &'b LocalCrateContext<'tcx> {
&self.local_ccxs[self.index]
self.local_ccx
}
pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
@ -688,10 +575,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
self.local().llcx
}
pub fn previous_work_product(&self) -> Option<&WorkProduct> {
self.local().previous_work_product.as_ref()
}
pub fn codegen_unit(&self) -> &CodegenUnit<'tcx> {
&self.local().codegen_unit
}
@ -700,14 +583,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) }
}
pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet {
&self.shared.exported_symbols
}
pub fn link_meta<'a>(&'a self) -> &'a LinkMeta {
&self.shared.link_meta
}
pub fn needs_unwind_cleanup_cache(&self) -> &RefCell<FxHashMap<Ty<'tcx>, bool>> {
&self.local().needs_unwind_cleanup_cache
}
@ -777,7 +652,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
}
pub fn stats<'a>(&'a self) -> &'a Stats {
&self.shared.stats
&self.local().stats
}
pub fn int_type(&self) -> Type {

View File

@ -26,7 +26,7 @@ use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor,
DICompositeType, DILexicalBlock, DIFlags};
use rustc::hir::def::CtorKind;
use rustc::hir::def_id::DefId;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::ty::fold::TypeVisitor;
use rustc::ty::subst::Substs;
use rustc::ty::util::TypeIdHasher;
@ -810,7 +810,7 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
};
fn fallback_path(scc: &SharedCrateContext) -> CString {
CString::new(scc.link_meta().crate_name.to_string()).unwrap()
CString::new(scc.tcx().crate_name(LOCAL_CRATE).to_string()).unwrap()
}
}

View File

@ -37,7 +37,7 @@ pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool
// visible). It might better to use the `exported_items` set from
// `driver::CrateAnalysis` in the future, but (atm) this set is not
// available in the translation pass.
!cx.exported_symbols().contains(&node_id)
!cx.shared().exported_symbols().contains(&node_id)
}
#[allow(non_snake_case)]

View File

@ -40,6 +40,7 @@
#![feature(conservative_impl_trait)]
use rustc::dep_graph::WorkProduct;
use syntax_pos::symbol::Symbol;
extern crate flate;
extern crate libc;
@ -165,6 +166,7 @@ unsafe impl Send for ModuleTranslation { }
unsafe impl Sync for ModuleTranslation { }
pub struct CrateTranslation {
pub crate_name: Symbol,
pub modules: Vec<ModuleTranslation>,
pub metadata_module: ModuleTranslation,
pub link: middle::cstore::LinkMeta,

View File

@ -11,7 +11,7 @@
#![allow(non_upper_case_globals)]
use llvm;
use llvm::{TypeRef, Bool, False, True, TypeKind};
use llvm::{ContextRef, TypeRef, Bool, False, True, TypeKind};
use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
use context::CrateContext;
@ -82,6 +82,10 @@ impl Type {
ty!(llvm::LLVMInt8TypeInContext(ccx.llcx()))
}
pub fn i8_llcx(llcx: ContextRef) -> Type {
ty!(llvm::LLVMInt8TypeInContext(llcx))
}
pub fn i16(ccx: &CrateContext) -> Type {
ty!(llvm::LLVMInt16TypeInContext(ccx.llcx()))
}
@ -123,6 +127,10 @@ impl Type {
Type::i8(ccx).ptr_to()
}
pub fn i8p_llcx(llcx: ContextRef) -> Type {
Type::i8_llcx(llcx).ptr_to()
}
pub fn int(ccx: &CrateContext) -> Type {
match &ccx.tcx().sess.target.target.target_pointer_width[..] {
"16" => Type::i16(ccx),