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 metadata::csearch;
use metadata::cstore;
use metadata::cstore::CStore;
use metadata::decoder;
use metadata::loader;
use metadata::loader::Os;
@ -38,6 +39,13 @@ use syntax::parse::token;
use syntax::crateid::CrateId;
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
// libraries necessary for later resolving, typechecking, linking, etc.
pub fn read_crates(sess: &Session,
@ -47,16 +55,13 @@ pub fn read_crates(sess: &Session,
let mut e = Env {
sess: sess,
os: os,
crate_cache: @RefCell::new(Vec::new()),
next_crate_num: 1,
next_crate_num: sess.cstore.next_crate_num(),
intr: intr
};
visit_crate(&e, krate);
visit::walk_crate(&mut e, krate, ());
dump_crates(e.crate_cache.borrow().as_slice());
warn_if_multiple_versions(&mut e,
sess.diagnostic(),
e.crate_cache.borrow().as_slice());
dump_crates(&sess.cstore);
warn_if_multiple_versions(sess.diagnostic(), &sess.cstore)
}
impl<'a> visit::Visitor<()> for Env<'a> {
@ -70,55 +75,36 @@ impl<'a> visit::Visitor<()> for Env<'a> {
}
}
#[deriving(Clone)]
struct cache_entry {
cnum: ast::CrateNum,
span: Span,
hash: Svh,
crate_id: CrateId,
}
fn dump_crates(crate_cache: &[cache_entry]) {
fn dump_crates(cstore: &CStore) {
debug!("resolved crates:");
for entry in crate_cache.iter() {
debug!("cnum: {:?}", entry.cnum);
debug!("span: {:?}", entry.span);
debug!("hash: {:?}", entry.hash);
}
cstore.iter_crate_data(|_, data| {
debug!("crate_id: {}", data.crate_id());
debug!(" cnum: {}", data.cnum);
debug!(" hash: {}", data.hash());
})
}
fn warn_if_multiple_versions(e: &mut Env,
diag: &SpanHandler,
crate_cache: &[cache_entry]) {
if crate_cache.len() != 0u {
let name = crate_cache[crate_cache.len() - 1].crate_id.name.clone();
fn warn_if_multiple_versions(diag: &SpanHandler, cstore: &CStore) {
let mut map = HashMap::new();
let (matches, non_matches) = crate_cache.partitioned(|entry|
name == entry.crate_id.name);
cstore.iter_crate_data(|cnum, data| {
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());
if matches.len() != 1u {
diag.handler().warn(
format!("using multiple versions of crate `{}`", name));
for match_ in matches.iter() {
diag.span_note(match_.span, "used here");
loader::note_crateid_attr(diag, &match_.crate_id);
}
for ((name, _), dupes) in map.move_iter() {
if dupes.len() == 1 { continue }
diag.handler().warn(
format!("using multiple versions of crate `{}`", name));
for dupe in dupes.move_iter() {
let data = cstore.get_crate_data(dupe);
diag.span_note(data.span, "used here");
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) {
for a in c.attrs.iter().filter(|m| m.name().equiv(&("link_args"))) {
match a.value_str() {
@ -269,14 +255,18 @@ fn visit_item(e: &Env, i: &ast::Item) {
fn existing_match(e: &Env, crate_id: &CrateId,
hash: Option<&Svh>) -> Option<ast::CrateNum> {
for c in e.crate_cache.borrow().iter() {
if !crate_id.matches(&c.crate_id) { continue }
match hash {
Some(hash) if *hash != c.hash => {}
Some(..) | None => return Some(c.cnum)
let mut ret = None;
e.sess.cstore.iter_crate_data(|cnum, data| {
let other_id = data.crate_id();
if crate_id.matches(&other_id) {
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,
@ -304,17 +294,8 @@ fn resolve_crate<'a>(e: &mut Env,
dylib, rlib, metadata
} = 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
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;
// 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 };
// Now resolve the crates referenced by this crate
let cnum_map = resolve_crate_deps(e,
root,
metadata.as_slice(),
span);
let cnum_map = resolve_crate_deps(e, root, metadata.as_slice(),
span);
let cmeta = @cstore::crate_metadata {
name: load_ctxt.crate_id.name.to_owned(),
data: metadata,
cnum_map: cnum_map,
cnum: cnum
cnum: cnum,
span: span,
};
e.sess.cstore.set_crate_data(cnum, cmeta);
@ -390,8 +370,7 @@ impl<'a> Loader<'a> {
env: Env {
sess: sess,
os: os,
crate_cache: @RefCell::new(Vec::new()),
next_crate_num: 1,
next_crate_num: sess.cstore.next_crate_num(),
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();
MacroCrate {
lib: library.dylib,
cnum: cnum
cnum: cnum,
}
}

View File

@ -22,6 +22,8 @@ use std::c_vec::CVec;
use std::rc::Rc;
use collections::HashMap;
use syntax::ast;
use syntax::crateid::CrateId;
use syntax::codemap::Span;
use syntax::parse::token::IdentInterner;
// 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 cnum_map: cnum_map,
pub cnum: ast::CrateNum,
pub span: Span,
}
#[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 {
*self.metas.borrow().get(&cnum)
}
@ -121,6 +128,9 @@ impl CStore {
.map(|source| source.clone())
}
pub fn dump_phase_syntax_crates(&self) {
}
pub fn reset(&self) {
self.metas.borrow_mut().clear();
self.extern_mod_crate_map.borrow_mut().clear();
@ -202,6 +212,8 @@ impl CStore {
impl crate_metadata {
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 {