blob: e6df6a2469f379963c956026a552485281e1679b [file] [log] [blame] [edit]
use std::ffi::CString;
use std::sync::Arc;
use rustc_data_structures::memmap::Mmap;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportLevel};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{CrateType, Lto};
use tracing::info;
use crate::back::symbol_export::{self, allocator_shim_symbols, symbol_name_for_instance_in_crate};
use crate::back::write::CodegenContext;
use crate::base::allocator_kind_for_codegen;
use crate::errors::{DynamicLinkingWithLTO, LtoDisallowed, LtoDylib, LtoProcMacro};
use crate::traits::*;
pub struct ThinModule<B: WriteBackendMethods> {
pub shared: Arc<ThinShared<B>>,
pub idx: usize,
}
impl<B: WriteBackendMethods> ThinModule<B> {
pub fn name(&self) -> &str {
self.shared.module_names[self.idx].to_str().unwrap()
}
pub fn cost(&self) -> u64 {
// Yes, that's correct, we're using the size of the bytecode as an
// indicator for how costly this codegen unit is.
self.data().len() as u64
}
pub fn data(&self) -> &[u8] {
let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data());
a.unwrap_or_else(|| {
let len = self.shared.thin_buffers.len();
self.shared.serialized_modules[self.idx - len].data()
})
}
}
pub struct ThinShared<B: WriteBackendMethods> {
pub data: B::ThinData,
pub thin_buffers: Vec<B::ThinBuffer>,
pub serialized_modules: Vec<SerializedModule<B::ModuleBuffer>>,
pub module_names: Vec<CString>,
}
pub enum SerializedModule<M: ModuleBufferMethods> {
Local(M),
FromRlib(Vec<u8>),
FromUncompressedFile(Mmap),
}
impl<M: ModuleBufferMethods> SerializedModule<M> {
pub fn data(&self) -> &[u8] {
match *self {
SerializedModule::Local(ref m) => m.data(),
SerializedModule::FromRlib(ref m) => m,
SerializedModule::FromUncompressedFile(ref m) => m,
}
}
}
fn crate_type_allows_lto(crate_type: CrateType) -> bool {
match crate_type {
CrateType::Executable
| CrateType::Dylib
| CrateType::Staticlib
| CrateType::Cdylib
| CrateType::ProcMacro
| CrateType::Sdylib => true,
CrateType::Rlib => false,
}
}
pub(super) fn exported_symbols_for_lto(
tcx: TyCtxt<'_>,
each_linked_rlib_for_lto: &[CrateNum],
) -> Vec<String> {
let export_threshold = match tcx.sess.lto() {
// We're just doing LTO for our one crate
Lto::ThinLocal => SymbolExportLevel::Rust,
// We're doing LTO for the entire crate graph
Lto::Fat | Lto::Thin => symbol_export::crates_export_threshold(&tcx.crate_types()),
Lto::No => return vec![],
};
let copy_symbols = |cnum| {
tcx.exported_non_generic_symbols(cnum)
.iter()
.chain(tcx.exported_generic_symbols(cnum))
.filter_map(|&(s, info): &(ExportedSymbol<'_>, SymbolExportInfo)| {
if info.level.is_below_threshold(export_threshold) || info.used {
Some(symbol_name_for_instance_in_crate(tcx, s, cnum))
} else {
None
}
})
.collect::<Vec<_>>()
};
let mut symbols_below_threshold = {
let _timer = tcx.prof.generic_activity("lto_generate_symbols_below_threshold");
copy_symbols(LOCAL_CRATE)
};
info!("{} symbols to preserve in this crate", symbols_below_threshold.len());
// If we're performing LTO for the entire crate graph, then for each of our
// upstream dependencies, include their exported symbols.
if tcx.sess.lto() != Lto::ThinLocal {
for &cnum in each_linked_rlib_for_lto {
let _timer = tcx.prof.generic_activity("lto_generate_symbols_below_threshold");
symbols_below_threshold.extend(copy_symbols(cnum));
}
}
// Mark allocator shim symbols as exported only if they were generated.
if export_threshold == SymbolExportLevel::Rust && allocator_kind_for_codegen(tcx).is_some() {
symbols_below_threshold.extend(allocator_shim_symbols(tcx).map(|(name, _kind)| name));
}
symbols_below_threshold
}
pub(super) fn check_lto_allowed<B: WriteBackendMethods>(cgcx: &CodegenContext<B>) {
if cgcx.lto == Lto::ThinLocal {
// Crate local LTO is always allowed
return;
}
let dcx = cgcx.create_dcx();
// Make sure we actually can run LTO
for crate_type in cgcx.crate_types.iter() {
if !crate_type_allows_lto(*crate_type) {
dcx.handle().emit_fatal(LtoDisallowed);
} else if *crate_type == CrateType::Dylib {
if !cgcx.opts.unstable_opts.dylib_lto {
dcx.handle().emit_fatal(LtoDylib);
}
} else if *crate_type == CrateType::ProcMacro && !cgcx.opts.unstable_opts.dylib_lto {
dcx.handle().emit_fatal(LtoProcMacro);
}
}
if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
dcx.handle().emit_fatal(DynamicLinkingWithLTO);
}
}