rustc: Use CStore, not a separate crate cache

This separate crate cache is one factor which is causing libstd to be loaded
twice during normal compilation. The crates loaded for syntax extensions have a
separate cache than the crates loaded for linking, so all crates are loaded once
per #[phase] they're tagged with.

This removes the cache and instead uses the CStore structure itself as the cache
for loaded crates. This should allow crates loaded during the syntax phase to be
shared with the crates loaded during the link phase.
This commit is contained in:
Alex Crichton 2014-04-07 12:14:33 -07:00
parent ef37cfdecc
commit 31755e2452
2 changed files with 61 additions and 70 deletions

View File

@ -18,6 +18,7 @@ use driver::{driver, session};
use driver::session::Session; use driver::session::Session;
use metadata::csearch; use metadata::csearch;
use metadata::cstore; use metadata::cstore;
use metadata::cstore::CStore;
use metadata::decoder; use metadata::decoder;
use metadata::loader; use metadata::loader;
use metadata::loader::Os; use metadata::loader::Os;
@ -38,6 +39,13 @@ use syntax::parse::token;
use syntax::crateid::CrateId; use syntax::crateid::CrateId;
use syntax::visit; use syntax::visit;
struct Env<'a> {
sess: &'a Session,
os: loader::Os,
next_crate_num: ast::CrateNum,
intr: Rc<IdentInterner>
}
// Traverses an AST, reading all the information about use'd crates and extern // Traverses an AST, reading all the information about use'd crates and extern
// libraries necessary for later resolving, typechecking, linking, etc. // libraries necessary for later resolving, typechecking, linking, etc.
pub fn read_crates(sess: &Session, pub fn read_crates(sess: &Session,
@ -47,16 +55,13 @@ pub fn read_crates(sess: &Session,
let mut e = Env { let mut e = Env {
sess: sess, sess: sess,
os: os, os: os,
crate_cache: @RefCell::new(Vec::new()), next_crate_num: sess.cstore.next_crate_num(),
next_crate_num: 1,
intr: intr intr: intr
}; };
visit_crate(&e, krate); visit_crate(&e, krate);
visit::walk_crate(&mut e, krate, ()); visit::walk_crate(&mut e, krate, ());
dump_crates(e.crate_cache.borrow().as_slice()); dump_crates(&sess.cstore);
warn_if_multiple_versions(&mut e, warn_if_multiple_versions(sess.diagnostic(), &sess.cstore)
sess.diagnostic(),
e.crate_cache.borrow().as_slice());
} }
impl<'a> visit::Visitor<()> for Env<'a> { impl<'a> visit::Visitor<()> for Env<'a> {
@ -70,55 +75,36 @@ impl<'a> visit::Visitor<()> for Env<'a> {
} }
} }
#[deriving(Clone)] fn dump_crates(cstore: &CStore) {
struct cache_entry {
cnum: ast::CrateNum,
span: Span,
hash: Svh,
crate_id: CrateId,
}
fn dump_crates(crate_cache: &[cache_entry]) {
debug!("resolved crates:"); debug!("resolved crates:");
for entry in crate_cache.iter() { cstore.iter_crate_data(|_, data| {
debug!("cnum: {:?}", entry.cnum); debug!("crate_id: {}", data.crate_id());
debug!("span: {:?}", entry.span); debug!(" cnum: {}", data.cnum);
debug!("hash: {:?}", entry.hash); debug!(" hash: {}", data.hash());
} })
} }
fn warn_if_multiple_versions(e: &mut Env, fn warn_if_multiple_versions(diag: &SpanHandler, cstore: &CStore) {
diag: &SpanHandler, let mut map = HashMap::new();
crate_cache: &[cache_entry]) {
if crate_cache.len() != 0u {
let name = crate_cache[crate_cache.len() - 1].crate_id.name.clone();
let (matches, non_matches) = crate_cache.partitioned(|entry| cstore.iter_crate_data(|cnum, data| {
name == entry.crate_id.name); let crateid = data.crate_id();
let key = (crateid.name.clone(), crateid.path.clone());
map.find_or_insert_with(key, |_| Vec::new()).push(cnum);
});
assert!(!matches.is_empty()); for ((name, _), dupes) in map.move_iter() {
if dupes.len() == 1 { continue }
if matches.len() != 1u { diag.handler().warn(
diag.handler().warn( format!("using multiple versions of crate `{}`", name));
format!("using multiple versions of crate `{}`", name)); for dupe in dupes.move_iter() {
for match_ in matches.iter() { let data = cstore.get_crate_data(dupe);
diag.span_note(match_.span, "used here"); diag.span_note(data.span, "used here");
loader::note_crateid_attr(diag, &match_.crate_id); loader::note_crateid_attr(diag, &data.crate_id());
}
} }
warn_if_multiple_versions(e, diag, non_matches);
} }
} }
struct Env<'a> {
sess: &'a Session,
os: loader::Os,
crate_cache: @RefCell<Vec<cache_entry>>,
next_crate_num: ast::CrateNum,
intr: Rc<IdentInterner>
}
fn visit_crate(e: &Env, c: &ast::Crate) { fn visit_crate(e: &Env, c: &ast::Crate) {
for a in c.attrs.iter().filter(|m| m.name().equiv(&("link_args"))) { for a in c.attrs.iter().filter(|m| m.name().equiv(&("link_args"))) {
match a.value_str() { match a.value_str() {
@ -269,14 +255,18 @@ fn visit_item(e: &Env, i: &ast::Item) {
fn existing_match(e: &Env, crate_id: &CrateId, fn existing_match(e: &Env, crate_id: &CrateId,
hash: Option<&Svh>) -> Option<ast::CrateNum> { hash: Option<&Svh>) -> Option<ast::CrateNum> {
for c in e.crate_cache.borrow().iter() { let mut ret = None;
if !crate_id.matches(&c.crate_id) { continue } e.sess.cstore.iter_crate_data(|cnum, data| {
match hash { let other_id = data.crate_id();
Some(hash) if *hash != c.hash => {} if crate_id.matches(&other_id) {
Some(..) | None => return Some(c.cnum) let other_hash = data.hash();
match hash {
Some(hash) if *hash != other_hash => {}
Some(..) | None => { ret = Some(cnum); }
}
} }
} });
None return ret;
} }
fn resolve_crate<'a>(e: &mut Env, fn resolve_crate<'a>(e: &mut Env,
@ -304,17 +294,8 @@ fn resolve_crate<'a>(e: &mut Env,
dylib, rlib, metadata dylib, rlib, metadata
} = load_ctxt.load_library_crate(root); } = load_ctxt.load_library_crate(root);
let crate_id = decoder::get_crate_id(metadata.as_slice());
let hash = decoder::get_crate_hash(metadata.as_slice());
// Claim this crate number and cache it // Claim this crate number and cache it
let cnum = e.next_crate_num; let cnum = e.next_crate_num;
e.crate_cache.borrow_mut().push(cache_entry {
cnum: cnum,
span: span,
hash: hash,
crate_id: crate_id,
});
e.next_crate_num += 1; e.next_crate_num += 1;
// Stash paths for top-most crate locally if necessary. // Stash paths for top-most crate locally if necessary.
@ -331,16 +312,15 @@ fn resolve_crate<'a>(e: &mut Env,
let root = if root.is_some() { root } else { &crate_paths }; let root = if root.is_some() { root } else { &crate_paths };
// Now resolve the crates referenced by this crate // Now resolve the crates referenced by this crate
let cnum_map = resolve_crate_deps(e, let cnum_map = resolve_crate_deps(e, root, metadata.as_slice(),
root, span);
metadata.as_slice(),
span);
let cmeta = @cstore::crate_metadata { let cmeta = @cstore::crate_metadata {
name: load_ctxt.crate_id.name.to_owned(), name: load_ctxt.crate_id.name.to_owned(),
data: metadata, data: metadata,
cnum_map: cnum_map, cnum_map: cnum_map,
cnum: cnum cnum: cnum,
span: span,
}; };
e.sess.cstore.set_crate_data(cnum, cmeta); e.sess.cstore.set_crate_data(cnum, cmeta);
@ -390,8 +370,7 @@ impl<'a> Loader<'a> {
env: Env { env: Env {
sess: sess, sess: sess,
os: os, os: os,
crate_cache: @RefCell::new(Vec::new()), next_crate_num: sess.cstore.next_crate_num(),
next_crate_num: 1,
intr: token::get_ident_interner(), intr: token::get_ident_interner(),
} }
} }
@ -406,7 +385,7 @@ impl<'a> CrateLoader for Loader<'a> {
let library = self.env.sess.cstore.get_used_crate_source(cnum).unwrap(); let library = self.env.sess.cstore.get_used_crate_source(cnum).unwrap();
MacroCrate { MacroCrate {
lib: library.dylib, lib: library.dylib,
cnum: cnum cnum: cnum,
} }
} }

View File

@ -22,6 +22,8 @@ use std::c_vec::CVec;
use std::rc::Rc; use std::rc::Rc;
use collections::HashMap; use collections::HashMap;
use syntax::ast; use syntax::ast;
use syntax::crateid::CrateId;
use syntax::codemap::Span;
use syntax::parse::token::IdentInterner; use syntax::parse::token::IdentInterner;
// A map from external crate numbers (as decoded from some crate file) to // A map from external crate numbers (as decoded from some crate file) to
@ -40,6 +42,7 @@ pub struct crate_metadata {
pub data: MetadataBlob, pub data: MetadataBlob,
pub cnum_map: cnum_map, pub cnum_map: cnum_map,
pub cnum: ast::CrateNum, pub cnum: ast::CrateNum,
pub span: Span,
} }
#[deriving(Eq)] #[deriving(Eq)]
@ -88,6 +91,10 @@ impl CStore {
} }
} }
pub fn next_crate_num(&self) -> ast::CrateNum {
self.metas.borrow().len() as ast::CrateNum + 1
}
pub fn get_crate_data(&self, cnum: ast::CrateNum) -> @crate_metadata { pub fn get_crate_data(&self, cnum: ast::CrateNum) -> @crate_metadata {
*self.metas.borrow().get(&cnum) *self.metas.borrow().get(&cnum)
} }
@ -121,6 +128,9 @@ impl CStore {
.map(|source| source.clone()) .map(|source| source.clone())
} }
pub fn dump_phase_syntax_crates(&self) {
}
pub fn reset(&self) { pub fn reset(&self) {
self.metas.borrow_mut().clear(); self.metas.borrow_mut().clear();
self.extern_mod_crate_map.borrow_mut().clear(); self.extern_mod_crate_map.borrow_mut().clear();
@ -202,6 +212,8 @@ impl CStore {
impl crate_metadata { impl crate_metadata {
pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() } pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
pub fn crate_id(&self) -> CrateId { decoder::get_crate_id(self.data()) }
pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
} }
impl MetadataBlob { impl MetadataBlob {