From 1a24a591dd43c53de7e3f16eff9f67469cf7a52b Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Wed, 26 Apr 2017 23:22:45 +0200 Subject: [PATCH] Remove rustc_llvm dependency from rustc_metadata Move the code for loading metadata from rlibs and dylibs from rustc_metadata into rustc_trans, and introduce a trait to avoid introducing a direct dependency on rustc_trans. This means rustc_metadata is no longer rebuilt when LLVM changes. --- src/Cargo.lock | 19 ++- src/librustc/Cargo.toml | 1 + src/librustc/lib.rs | 1 + src/librustc/middle/cstore.rs | 32 +++- src/librustc_driver/lib.rs | 10 +- src/librustc_driver/test.rs | 3 +- src/librustc_metadata/Cargo.toml | 2 +- src/librustc_metadata/creader.rs | 2 + src/librustc_metadata/cstore.rs | 15 +- src/librustc_metadata/cstore_impl.rs | 21 +-- src/librustc_metadata/decoder.rs | 6 +- src/librustc_metadata/lib.rs | 2 +- src/librustc_metadata/locator.rs | 225 ++++++++------------------- src/librustc_trans/Cargo.toml | 1 + src/librustc_trans/back/archive.rs | 5 +- src/librustc_trans/back/link.rs | 9 +- src/librustc_trans/base.rs | 4 +- src/librustc_trans/lib.rs | 4 + src/librustc_trans/metadata.rs | 122 +++++++++++++++ src/librustdoc/core.rs | 3 +- src/librustdoc/test.rs | 5 +- src/test/run-make/issue-19371/foo.rs | 3 +- 22 files changed, 276 insertions(+), 219 deletions(-) create mode 100644 src/librustc_trans/metadata.rs diff --git a/src/Cargo.lock b/src/Cargo.lock index 776a268aa8d..bd9fda42570 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -316,6 +316,14 @@ name = "open" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "owning_ref" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "panic_abort" version = "0.0.0" @@ -442,6 +450,7 @@ dependencies = [ "fmt_macros 0.0.0", "graphviz 0.0.0", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", @@ -626,13 +635,13 @@ version = "0.0.0" dependencies = [ "flate 0.0.0", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", - "rustc_llvm 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_ext 0.0.0", @@ -734,6 +743,7 @@ version = "0.0.0" dependencies = [ "flate 0.0.0", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", @@ -820,6 +830,11 @@ dependencies = [ name = "serialize" version = "0.0.0" +[[package]] +name = "stable_deref_trait" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "std" version = "0.0.0" @@ -1015,6 +1030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" "checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" +"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" "checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" @@ -1026,6 +1042,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0" "checksum serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "a702319c807c016e51f672e5c77d6f0b46afddd744b5e437d6b8436b888b458f" "checksum serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc45439552eb8fb86907a2c41c1fd0ef97458efb87ff7f878db466eb581824e" +"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a" "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index fa217acd9f9..3c762e43e9a 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -13,6 +13,7 @@ arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } log = "0.3" +owning_ref = "0.3.3" rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 5cf26ea8bfc..c979677ff71 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -54,6 +54,7 @@ extern crate getopts; extern crate graphviz; extern crate libc; +extern crate owning_ref; extern crate rustc_llvm as llvm; extern crate rustc_back; extern crate rustc_data_structures; diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 569b1aeeb09..a68aca46000 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -36,8 +36,9 @@ use util::nodemap::{NodeSet, DefIdMap}; use std::any::Any; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::rc::Rc; +use owning_ref::ErasedBoxRef; use syntax::ast; use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; @@ -201,11 +202,33 @@ pub fn new() -> EncodedMetadataHashes { } } +/// The backend's way to give the crate store access to the metadata in a library. +/// Note that it returns the raw metadata bytes stored in the library file, whether +/// it is compressed, uncompressed, some weird mix, etc. +/// rmeta files are backend independent and not handled here. +/// +/// At the time of this writing, there is only one backend and one way to store +/// metadata in library -- this trait just serves to decouple rustc_metadata from +/// the archive reader, which depends on LLVM. +pub trait MetadataLoader { + fn get_rlib_metadata(&self, + target: &Target, + filename: &Path) + -> Result, String>; + fn get_dylib_metadata(&self, + target: &Target, + filename: &Path) + -> Result, String>; +} + /// A store of Rust crates, through with their metadata /// can be accessed. pub trait CrateStore { fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc; + // access to the metadata loader + fn metadata_loader(&self) -> &MetadataLoader; + // item info fn visibility(&self, def: DefId) -> ty::Visibility; fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap>; @@ -275,8 +298,6 @@ fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) fn used_link_args(&self) -> Vec; // utility functions - fn metadata_filename(&self) -> &str; - fn metadata_section_name(&self, target: &Target) -> &str; fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>; fn used_crate_source(&self, cnum: CrateNum) -> CrateSource; fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; @@ -413,8 +434,6 @@ fn used_libraries(&self) -> Vec { vec![] } fn used_link_args(&self) -> Vec { vec![] } // utility functions - fn metadata_filename(&self) -> &str { bug!("metadata_filename") } - fn metadata_section_name(&self, target: &Target) -> &str { bug!("metadata_section_name") } fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)> { vec![] } fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") } @@ -427,6 +446,9 @@ fn encode_metadata<'a, 'tcx>(&self, bug!("encode_metadata") } fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } + + // access to the metadata loader + fn metadata_loader(&self) -> &MetadataLoader { bug!("metadata_loader") } } pub trait CrateLoader { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 024fc546a15..2dab680ad45 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -204,7 +204,7 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => { }; let dep_graph = DepGraph::new(sopts.build_dep_graph()); - let cstore = Rc::new(CStore::new(&dep_graph)); + let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader)); let loader = file_loader.unwrap_or(box RealFileLoader); let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping())); @@ -409,7 +409,7 @@ fn no_input(&mut self, return None; } let dep_graph = DepGraph::new(sopts.build_dep_graph()); - let cstore = Rc::new(CStore::new(&dep_graph)); + let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader)); let mut sess = build_session(sopts.clone(), &dep_graph, None, @@ -558,7 +558,11 @@ pub fn list_metadata(sess: &Session, matches: &getopts::Matches, input: &Input) &Input::File(ref ifile) => { let path = &(*ifile); let mut v = Vec::new(); - locator::list_file_metadata(&sess.target.target, path, &mut v).unwrap(); + locator::list_file_metadata(&sess.target.target, + path, + sess.cstore.metadata_loader(), + &mut v) + .unwrap(); println!("{}", String::from_utf8(v).unwrap()); } &Input::Str { .. } => { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index e2cbc480715..be4f64b7109 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -14,6 +14,7 @@ use rustc::dep_graph::DepGraph; use rustc_lint; use rustc_resolve::MakeGlobMap; +use rustc_trans; use rustc::middle::lang_items; use rustc::middle::free_region::FreeRegionMap; use rustc::middle::region::{CodeExtent, RegionMaps}; @@ -104,7 +105,7 @@ fn test_env(source_string: &str, let dep_graph = DepGraph::new(false); let _ignore = dep_graph.in_ignore(); - let cstore = Rc::new(CStore::new(&dep_graph)); + let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader)); let sess = session::build_session_(options, &dep_graph, None, diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index e8b90609273..f47788ee036 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -11,13 +11,13 @@ crate-type = ["dylib"] [dependencies] flate = { path = "../libflate" } log = "0.3" +owning_ref = "0.3.3" proc_macro = { path = "../libproc_macro" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } -rustc_llvm = { path = "../librustc_llvm" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index d2874f16289..dc7be42e452 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -393,6 +393,7 @@ fn resolve_crate(&mut self, rejected_via_filename: vec![], should_match_name: true, is_proc_macro: Some(false), + metadata_loader: &*self.cstore.metadata_loader, }; self.load(&mut locate_ctxt).or_else(|| { @@ -554,6 +555,7 @@ fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> Extens rejected_via_filename: vec![], should_match_name: true, is_proc_macro: None, + metadata_loader: &*self.cstore.metadata_loader, }; let library = self.load(&mut locate_ctxt).or_else(|| { if !is_cross { diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index c12b4209675..d2ad6d0ab34 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -11,21 +11,20 @@ // The crate store - a central repo for information collected about external // crates and libraries -use locator; use schema::{self, Tracked}; use rustc::dep_graph::{DepGraph, DepNode, GlobalMetaDataKind}; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefIndex, DefId}; use rustc::hir::map::definitions::DefPathTable; use rustc::hir::svh::Svh; -use rustc::middle::cstore::{DepKind, ExternCrate}; +use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader}; use rustc_back::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; use rustc::util::nodemap::{FxHashMap, FxHashSet, NodeMap, DefIdMap}; use std::cell::{RefCell, Cell}; use std::rc::Rc; -use flate::Bytes; +use owning_ref::ErasedBoxRef; use syntax::{ast, attr}; use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; @@ -43,11 +42,7 @@ // own crate numbers. pub type CrateNumMap = IndexVec; -pub enum MetadataBlob { - Inflated(Bytes), - Archive(locator::ArchiveMetadata), - Raw(Vec), -} +pub struct MetadataBlob(pub ErasedBoxRef<[u8]>); /// Holds information about a syntax_pos::FileMap imported from another crate. /// See `imported_filemaps()` for more information. @@ -103,10 +98,11 @@ pub struct CStore { statically_included_foreign_items: RefCell>, pub dllimport_foreign_items: RefCell>, pub visible_parent_map: RefCell>, + pub metadata_loader: Box, } impl CStore { - pub fn new(dep_graph: &DepGraph) -> CStore { + pub fn new(dep_graph: &DepGraph, metadata_loader: Box) -> CStore { CStore { dep_graph: dep_graph.clone(), metas: RefCell::new(FxHashMap()), @@ -116,6 +112,7 @@ pub fn new(dep_graph: &DepGraph) -> CStore { statically_included_foreign_items: RefCell::new(FxHashSet()), dllimport_foreign_items: RefCell::new(FxHashSet()), visible_parent_map: RefCell::new(FxHashMap()), + metadata_loader: metadata_loader, } } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index dbf3e94832f..1a2298d3fb1 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -10,12 +10,11 @@ use cstore; use encoder; -use locator; use schema; use rustc::dep_graph::DepTrackingMapConfig; use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, - ExternCrate, NativeLibrary, LinkMeta, + ExternCrate, NativeLibrary, MetadataLoader, LinkMeta, LinkagePreference, LoadedMacro, EncodedMetadata}; use rustc::hir::def; use rustc::middle::lang_items; @@ -38,7 +37,6 @@ use syntax::symbol::Symbol; use syntax_pos::{Span, NO_EXPANSION}; use rustc::hir::svh::Svh; -use rustc_back::target::Target; use rustc::hir; macro_rules! provide { @@ -135,6 +133,10 @@ fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc { self.get_crate_data(krate) } + fn metadata_loader(&self) -> &MetadataLoader { + &*self.metadata_loader + } + fn visibility(&self, def: DefId) -> ty::Visibility { self.dep_graph.read(DepNode::MetaData(def)); self.get_crate_data(def.krate).get_visibility(def.index) @@ -420,17 +422,6 @@ fn used_link_args(&self) -> Vec { self.get_used_link_args().borrow().clone() } - - fn metadata_filename(&self) -> &str - { - locator::METADATA_FILENAME - } - - fn metadata_section_name(&self, target: &Target) -> &str - { - locator::meta_section_name(target) - } - fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)> { self.do_get_used_crates(prefer) @@ -522,4 +513,4 @@ fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap> { drop(visible_parent_map); self.visible_parent_map.borrow() } -} +} \ No newline at end of file diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 819095e2628..c734b9f411c 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -77,11 +77,7 @@ fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob { fn raw_bytes(self) -> &'a [u8] { - match *self { - MetadataBlob::Inflated(ref vec) => vec, - MetadataBlob::Archive(ref ar) => ar.as_slice(), - MetadataBlob::Raw(ref vec) => vec, - } + &self.0 } } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 27555f49e57..e3d9e5ac74a 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -37,6 +37,7 @@ extern crate syntax_pos; extern crate flate; extern crate serialize as rustc_serialize; // used by deriving +extern crate owning_ref; extern crate rustc_errors as errors; extern crate syntax_ext; extern crate proc_macro; @@ -46,7 +47,6 @@ extern crate rustc_back; extern crate rustc_const_math; extern crate rustc_data_structures; -extern crate rustc_llvm; mod diagnostics; diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 84bb82de370..34b07af9f01 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -224,15 +224,12 @@ use schema::{METADATA_HEADER, rustc_version}; use rustc::hir::svh::Svh; +use rustc::middle::cstore::MetadataLoader; use rustc::session::{config, Session}; use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch}; use rustc::session::search_paths::PathKind; -use rustc::util::common; use rustc::util::nodemap::FxHashMap; -use rustc_llvm as llvm; -use rustc_llvm::{False, ObjectFile, mk_section_iter}; -use rustc_llvm::archive_ro::ArchiveRO; use errors::DiagnosticBuilder; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -243,11 +240,10 @@ use std::fs::{self, File}; use std::io::{self, Read}; use std::path::{Path, PathBuf}; -use std::ptr; -use std::slice; use std::time::Instant; use flate; +use owning_ref::{ErasedBoxRef, OwningRef}; pub struct CrateMismatch { path: PathBuf, @@ -272,12 +268,7 @@ pub struct Context<'a> { pub rejected_via_filename: Vec, pub should_match_name: bool, pub is_proc_macro: Option, -} - -pub struct ArchiveMetadata { - _archive: ArchiveRO, - // points into self._archive - data: *const [u8], + pub metadata_loader: &'a MetadataLoader, } pub struct CratePaths { @@ -287,8 +278,6 @@ pub struct CratePaths { pub rmeta: Option, } -pub const METADATA_FILENAME: &'static str = "rust.metadata.bin"; - #[derive(Copy, Clone, PartialEq)] enum CrateFlavor { Rlib, @@ -596,20 +585,21 @@ fn extract_one(&mut self, let mut err: Option = None; for (lib, kind) in m { info!("{} reading metadata from: {}", flavor, lib.display()); - let (hash, metadata) = match get_metadata_section(self.target, flavor, &lib) { - Ok(blob) => { - if let Some(h) = self.crate_matches(&blob, &lib) { - (h, blob) - } else { - info!("metadata mismatch"); + let (hash, metadata) = + match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) { + Ok(blob) => { + if let Some(h) = self.crate_matches(&blob, &lib) { + (h, blob) + } else { + info!("metadata mismatch"); + continue; + } + } + Err(err) => { + info!("no metadata found: {}", err); continue; } - } - Err(err) => { - info!("no metadata found: {}", err); - continue; - } - }; + }; // If we see multiple hashes, emit an error about duplicate candidates. if slot.as_ref().map_or(false, |s| s.0 != hash) { let mut e = struct_span_err!(self.sess, @@ -833,50 +823,14 @@ pub fn note_crate_name(err: &mut DiagnosticBuilder, name: &str) { err.note(&format!("crate name: {}", name)); } -impl ArchiveMetadata { - fn new(ar: ArchiveRO) -> Option { - let data = { - let section = ar.iter() - .filter_map(|s| s.ok()) - .find(|sect| sect.name() == Some(METADATA_FILENAME)); - match section { - Some(s) => s.data() as *const [u8], - None => { - debug!("didn't find '{}' in the archive", METADATA_FILENAME); - return None; - } - } - }; - - Some(ArchiveMetadata { - _archive: ar, - data: data, - }) - } - - pub fn as_slice<'a>(&'a self) -> &'a [u8] { - unsafe { &*self.data } - } -} - -fn verify_decompressed_encoding_version(blob: &MetadataBlob, - filename: &Path) - -> Result<(), String> { - if !blob.is_compatible() { - Err((format!("incompatible metadata version found: '{}'", - filename.display()))) - } else { - Ok(()) - } -} - // Just a small wrapper to time how long reading metadata takes. fn get_metadata_section(target: &Target, flavor: CrateFlavor, - filename: &Path) + filename: &Path, + loader: &MetadataLoader) -> Result { let start = Instant::now(); - let ret = get_metadata_section_imp(target, flavor, filename); + let ret = get_metadata_section_imp(target, flavor, filename, loader); info!("reading {:?} => {:?}", filename.file_name().unwrap(), start.elapsed()); @@ -885,118 +839,61 @@ fn get_metadata_section(target: &Target, fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, - filename: &Path) + filename: &Path, + loader: &MetadataLoader) -> Result { if !filename.exists() { return Err(format!("no such file: '{}'", filename.display())); } - if flavor == CrateFlavor::Rlib { - // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap - // internally to read the file. We also avoid even using a memcpy by - // just keeping the archive along while the metadata is in use. - let archive = match ArchiveRO::open(filename) { - Some(ar) => ar, - None => { - debug!("llvm didn't like `{}`", filename.display()); - return Err(format!("failed to read rlib metadata: '{}'", filename.display())); + let raw_bytes: ErasedBoxRef<[u8]> = match flavor { + CrateFlavor::Rlib => loader.get_rlib_metadata(target, filename)?, + CrateFlavor::Dylib => { + let buf = loader.get_dylib_metadata(target, filename)?; + // The header is uncompressed + let header_len = METADATA_HEADER.len(); + debug!("checking {} bytes of metadata-version stamp", header_len); + let header = &buf[..cmp::min(header_len, buf.len())]; + if header != METADATA_HEADER { + return Err(format!("incompatible metadata version found: '{}'", + filename.display())); } - }; - return match ArchiveMetadata::new(archive).map(|ar| MetadataBlob::Archive(ar)) { - None => Err(format!("failed to read rlib metadata: '{}'", filename.display())), - Some(blob) => { - verify_decompressed_encoding_version(&blob, filename)?; - Ok(blob) - } - }; - } else if flavor == CrateFlavor::Rmeta { - let mut file = File::open(filename).map_err(|_| - format!("could not open file: '{}'", filename.display()))?; - let mut buf = vec![]; - file.read_to_end(&mut buf).map_err(|_| - format!("failed to read rlib metadata: '{}'", filename.display()))?; - let blob = MetadataBlob::Raw(buf); - verify_decompressed_encoding_version(&blob, filename)?; - return Ok(blob); - } - unsafe { - let buf = common::path2cstr(filename); - let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()); - if mb as isize == 0 { - return Err(format!("error reading library: '{}'", filename.display())); - } - let of = match ObjectFile::new(mb) { - Some(of) => of, - _ => { - return Err((format!("provided path not an object file: '{}'", filename.display()))) - } - }; - let si = mk_section_iter(of.llof); - while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { - let mut name_buf = ptr::null(); - let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); - let name = slice::from_raw_parts(name_buf as *const u8, name_len as usize).to_vec(); - let name = String::from_utf8(name).unwrap(); - debug!("get_metadata_section: name {}", name); - if read_meta_section_name(target) == name { - let cbuf = llvm::LLVMGetSectionContents(si.llsi); - let csz = llvm::LLVMGetSectionSize(si.llsi) as usize; - let cvbuf: *const u8 = cbuf as *const u8; - let vlen = METADATA_HEADER.len(); - debug!("checking {} bytes of metadata-version stamp", vlen); - let minsz = cmp::min(vlen, csz); - let buf0 = slice::from_raw_parts(cvbuf, minsz); - let version_ok = buf0 == METADATA_HEADER; - if !version_ok { - return Err((format!("incompatible metadata version found: '{}'", - filename.display()))); - } - let cvbuf1 = cvbuf.offset(vlen as isize); - debug!("inflating {} bytes of compressed metadata", csz - vlen); - let bytes = slice::from_raw_parts(cvbuf1, csz - vlen); - match flate::inflate_bytes(bytes) { - Ok(inflated) => { - let blob = MetadataBlob::Inflated(inflated); - verify_decompressed_encoding_version(&blob, filename)?; - return Ok(blob); - } - Err(_) => {} + // Header is okay -> inflate the actual metadata + let compressed_bytes = &buf[header_len..]; + debug!("inflating {} bytes of compressed metadata", compressed_bytes.len()); + match flate::inflate_bytes(compressed_bytes) { + Ok(inflated) => { + let buf = unsafe { OwningRef::new_assert_stable_address(inflated) }; + buf.map_owner_box().erase_owner() + } + Err(_) => { + return Err(format!("failed to decompress metadata: {}", filename.display())); } } - llvm::LLVMMoveToNextSection(si.llsi); } - Err(format!("metadata not found: '{}'", filename.display())) - } -} - -pub fn meta_section_name(target: &Target) -> &'static str { - // Historical note: - // - // When using link.exe it was seen that the section name `.note.rustc` - // was getting shortened to `.note.ru`, and according to the PE and COFF - // specification: - // - // > Executable images do not use a string table and do not support - // > section names longer than 8 characters - // - // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx - // - // As a result, we choose a slightly shorter name! As to why - // `.note.rustc` works on MinGW, that's another good question... - - if target.options.is_like_osx { - "__DATA,.rustc" + CrateFlavor::Rmeta => { + let mut file = File::open(filename).map_err(|_| + format!("could not open file: '{}'", filename.display()))?; + let mut buf = vec![]; + file.read_to_end(&mut buf).map_err(|_| + format!("failed to read rmeta metadata: '{}'", filename.display()))?; + OwningRef::new(buf).map_owner_box().erase_owner() + } + }; + let blob = MetadataBlob(raw_bytes); + if blob.is_compatible() { + Ok(blob) } else { - ".rustc" + Err(format!("incompatible metadata version found: '{}'", filename.display())) } } -pub fn read_meta_section_name(_target: &Target) -> &'static str { - ".rustc" -} - // A diagnostic function for dumping crate metadata to an output stream -pub fn list_file_metadata(target: &Target, path: &Path, out: &mut io::Write) -> io::Result<()> { +pub fn list_file_metadata(target: &Target, + path: &Path, + loader: &MetadataLoader, + out: &mut io::Write) + -> io::Result<()> { let filename = path.file_name().unwrap().to_str().unwrap(); let flavor = if filename.ends_with(".rlib") { CrateFlavor::Rlib @@ -1005,7 +902,7 @@ pub fn list_file_metadata(target: &Target, path: &Path, out: &mut io::Write) -> } else { CrateFlavor::Dylib }; - match get_metadata_section(target, flavor, path) { + match get_metadata_section(target, flavor, path, loader) { Ok(metadata) => metadata.list_crate_metadata(out), Err(msg) => write!(out, "{}\n", msg), } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index af477f5a152..4ccc85257f3 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -12,6 +12,7 @@ test = false [dependencies] flate = { path = "../libflate" } log = "0.3" +owning_ref = "0.3.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 0f908b7d069..902065c8688 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -20,6 +20,7 @@ use libc; use llvm::archive_ro::{ArchiveRO, Child}; use llvm::{self, ArchiveKind}; +use metadata::METADATA_FILENAME; use rustc::session::Session; pub struct ArchiveConfig<'a> { @@ -158,11 +159,9 @@ pub fn add_rlib(&mut self, // Ignoring all bytecode files, no matter of // name let bc_ext = ".bytecode.deflate"; - let metadata_filename = - self.config.sess.cstore.metadata_filename().to_owned(); self.add_archive(rlib, move |fname: &str| { - if fname.ends_with(bc_ext) || fname == metadata_filename { + if fname.ends_with(bc_ext) || fname == METADATA_FILENAME { return true } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index e42e69d2a76..b8aabef65a9 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -13,6 +13,7 @@ use super::rpath::RPathConfig; use super::rpath; use super::msvc; +use metadata::METADATA_FILENAME; use session::config; use session::config::NoDebugInfo; use session::config::{OutputFilenames, Input, OutputType}; @@ -521,7 +522,7 @@ fn link_rlib<'a>(sess: &'a Session, // contain the metadata in a separate file. We use a temp directory // here so concurrent builds in the same directory don't try to use // the same filename for metadata (stomping over one another) - let metadata = tmpdir.join(sess.cstore.metadata_filename()); + let metadata = tmpdir.join(METADATA_FILENAME); emit_metadata(sess, trans, &metadata); ab.add_file(&metadata); @@ -1141,8 +1142,7 @@ fn link_sanitizer_runtime(cmd: &mut Linker, archive.update_symbols(); for f in archive.src_files() { - if f.ends_with("bytecode.deflate") || - f == sess.cstore.metadata_filename() { + if f.ends_with("bytecode.deflate") || f == METADATA_FILENAME { archive.remove_file(&f); continue } @@ -1217,8 +1217,7 @@ fn add_static_crate(cmd: &mut Linker, let mut any_objects = false; for f in archive.src_files() { - if f.ends_with("bytecode.deflate") || - f == sess.cstore.metadata_filename() { + if f.ends_with("bytecode.deflate") || f == METADATA_FILENAME { archive.remove_file(&f); continue } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 8689e176f7a..437ced85b2e 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -34,6 +34,7 @@ use back::symbol_export::{self, ExportedSymbols}; use llvm::{ContextRef, Linkage, ModuleRef, ValueRef, Vector, get_param}; use llvm; +use metadata; use rustc::hir::def_id::LOCAL_CRATE; use middle::lang_items::StartFnLangItem; use middle::cstore::EncodedMetadata; @@ -778,8 +779,7 @@ enum MetadataKind { }; unsafe { llvm::LLVMSetInitializer(llglobal, llconst); - let section_name = - tcx.sess.cstore.metadata_section_name(&tcx.sess.target.target); + let section_name = metadata::metadata_section_name(&tcx.sess.target.target); let name = CString::new(section_name).unwrap(); llvm::LLVMSetSection(llglobal, name.as_ptr()); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 8e633ee59b6..15a1b32a5fd 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -45,6 +45,7 @@ extern crate flate; extern crate libc; +extern crate owning_ref; #[macro_use] extern crate rustc; extern crate rustc_back; extern crate rustc_data_structures; @@ -70,6 +71,8 @@ pub use base::trans_crate; pub use back::symbol_names::provide; +pub use metadata::LlvmMetadataLoader; + pub mod back { pub use rustc::hir::svh; @@ -120,6 +123,7 @@ pub mod back { mod glue; mod intrinsic; mod machine; +mod metadata; mod meth; mod mir; mod monomorphize; diff --git a/src/librustc_trans/metadata.rs b/src/librustc_trans/metadata.rs new file mode 100644 index 00000000000..2c0148dfbb3 --- /dev/null +++ b/src/librustc_trans/metadata.rs @@ -0,0 +1,122 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::util::common; +use rustc::middle::cstore::MetadataLoader; +use rustc_back::target::Target; +use llvm; +use llvm::{False, ObjectFile, mk_section_iter}; +use llvm::archive_ro::ArchiveRO; + +use owning_ref::{ErasedBoxRef, OwningRef}; +use std::path::Path; +use std::ptr; +use std::slice; + +pub const METADATA_FILENAME: &str = "rust.metadata.bin"; + +pub struct LlvmMetadataLoader; + +impl MetadataLoader for LlvmMetadataLoader { + fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result, String> { + // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap + // internally to read the file. We also avoid even using a memcpy by + // just keeping the archive along while the metadata is in use. + let archive = ArchiveRO::open(filename) + .map(|ar| OwningRef::new(box ar)) + .ok_or_else(|| { + debug!("llvm didn't like `{}`", filename.display()); + format!("failed to read rlib metadata: '{}'", filename.display()) + })?; + let buf: OwningRef<_, [u8]> = archive + .try_map(|ar| { + ar.iter() + .filter_map(|s| s.ok()) + .find(|sect| sect.name() == Some(METADATA_FILENAME)) + .map(|s| s.data()) + .ok_or_else(|| { + debug!("didn't find '{}' in the archive", METADATA_FILENAME); + format!("failed to read rlib metadata: '{}'", + filename.display()) + }) + })?; + Ok(buf.erase_owner()) + } + + fn get_dylib_metadata(&self, + target: &Target, + filename: &Path) + -> Result, String> { + unsafe { + let buf = common::path2cstr(filename); + let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()); + if mb as isize == 0 { + return Err(format!("error reading library: '{}'", filename.display())); + } + let of = ObjectFile::new(mb) + .map(|of| OwningRef::new(box of)) + .ok_or_else(|| format!("provided path not an object file: '{}'", + filename.display()))?; + let buf = of.try_map(|of| search_meta_section(of, target, filename))?; + Ok(buf.erase_owner()) + } + } +} + +fn search_meta_section<'a>(of: &'a ObjectFile, + target: &Target, + filename: &Path) + -> Result<&'a [u8], String> { + unsafe { + let si = mk_section_iter(of.llof); + while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { + let mut name_buf = ptr::null(); + let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); + let name = slice::from_raw_parts(name_buf as *const u8, name_len as usize).to_vec(); + let name = String::from_utf8(name).unwrap(); + debug!("get_metadata_section: name {}", name); + if read_metadata_section_name(target) == name { + let cbuf = llvm::LLVMGetSectionContents(si.llsi); + let csz = llvm::LLVMGetSectionSize(si.llsi) as usize; + // The buffer is valid while the object file is around + let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz); + return Ok(buf); + } + llvm::LLVMMoveToNextSection(si.llsi); + } + } + Err(format!("metadata not found: '{}'", filename.display())) +} + +pub fn metadata_section_name(target: &Target) -> &'static str { + // Historical note: + // + // When using link.exe it was seen that the section name `.note.rustc` + // was getting shortened to `.note.ru`, and according to the PE and COFF + // specification: + // + // > Executable images do not use a string table and do not support + // > section names longer than 8 characters + // + // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx + // + // As a result, we choose a slightly shorter name! As to why + // `.note.rustc` works on MinGW, that's another good question... + + if target.options.is_like_osx { + "__DATA,.rustc" + } else { + ".rustc" + } +} + +fn read_metadata_section_name(_target: &Target) -> &'static str { + ".rustc" +} diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 9e2d8516333..d41e9931409 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -19,6 +19,7 @@ use rustc::hir::map as hir_map; use rustc::lint; use rustc::util::nodemap::FxHashMap; +use rustc_trans; use rustc_trans::back::link; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; @@ -138,7 +139,7 @@ pub fn run_core(search_paths: SearchPaths, let dep_graph = DepGraph::new(false); let _ignore = dep_graph.in_ignore(); - let cstore = Rc::new(CStore::new(&dep_graph)); + let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader)); let mut sess = session::build_session_( sessopts, &dep_graph, cpath, diagnostic_handler, codemap, cstore.clone() ); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index d5237d629cf..0600ae5b66e 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -34,6 +34,7 @@ use rustc_driver::driver::phase_2_configure_and_expand; use rustc_metadata::cstore::CStore; use rustc_resolve::MakeGlobMap; +use rustc_trans; use rustc_trans::back::link; use syntax::ast; use syntax::codemap::CodeMap; @@ -81,7 +82,7 @@ pub fn run(input: &str, let dep_graph = DepGraph::new(false); let _ignore = dep_graph.in_ignore(); - let cstore = Rc::new(CStore::new(&dep_graph)); + let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader)); let mut sess = session::build_session_( sessopts, &dep_graph, Some(input_path.clone()), handler, codemap.clone(), cstore.clone(), ); @@ -229,7 +230,7 @@ fn drop(&mut self) { let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter); let dep_graph = DepGraph::new(false); - let cstore = Rc::new(CStore::new(&dep_graph)); + let cstore = Rc::new(CStore::new(&dep_graph, box rustc_trans::LlvmMetadataLoader)); let mut sess = session::build_session_( sessopts, &dep_graph, None, diagnostic_handler, codemap, cstore.clone(), ); diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 0336fe277c5..74ecdab3372 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -15,6 +15,7 @@ extern crate rustc_lint; extern crate rustc_metadata; extern crate rustc_errors; +extern crate rustc_trans; extern crate syntax; use rustc::dep_graph::DepGraph; @@ -58,7 +59,7 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { let descriptions = Registry::new(&rustc::DIAGNOSTICS); let dep_graph = DepGraph::new(opts.build_dep_graph()); - let cstore = Rc::new(CStore::new(&dep_graph)); + let cstore = Rc::new(CStore::new(&dep_graph, Box::new(rustc_trans::LlvmMetadataLoader))); let sess = build_session(opts, &dep_graph, None, descriptions, cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); (sess, cstore) -- 2.44.0