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 { pub shared: Arc>, pub idx: usize, } impl ThinModule { 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 { pub data: B::ThinData, pub thin_buffers: Vec, pub serialized_modules: Vec>, pub module_names: Vec, } pub enum SerializedModule { Local(M), FromRlib(Vec), FromUncompressedFile(Mmap), } impl SerializedModule { 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 { 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::>() }; 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(cgcx: &CodegenContext) { 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); } }