From 47af3f1935ea9428354febf248ba41cb4726f74b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 28 Mar 2016 20:01:48 -0400 Subject: [PATCH 01/21] add MetaData DepNode variant --- src/librustc/dep_graph/dep_node.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 3e43c8e2c935..b81aa5822369 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -32,6 +32,12 @@ pub enum DepNode { // Represents the HIR node with the given node-id Hir(D), + // Represents the meta-data for a node. For local def-ids, this is + // created by trans. For remote def-ids, we add a read of this + // node each time we pull the information for an item out of the + // crate store. + MetaData(D), + // Represents different phases in the compiler. CrateReader, CollectLanguageItems, From 2237e899084f16f61e4a74c191a74c7bb2fd3727 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 28 Mar 2016 20:05:35 -0400 Subject: [PATCH 02/21] remove the `Any` bound from `CrateStore` This is a [breaking-change] for plugins, which ought by now to have stopped relying on downcasting. --- src/librustc/middle/cstore.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index c0af457ed236..85c31774cc44 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -150,12 +150,7 @@ pub struct ExternCrate { /// A store of Rust crates, through with their metadata /// can be accessed. -/// -/// The `: Any` bound is a temporary measure that allows access -/// to the backing `rustc_metadata::cstore::CStore` object. It -/// will be removed in the near future - if you need to access -/// internal APIs, please tell us. -pub trait CrateStore<'tcx> : Any { +pub trait CrateStore<'tcx> { // item info fn stability(&self, def: DefId) -> Option; fn deprecation(&self, def: DefId) -> Option; From b711734a5f7280cc3ceb99e09551a7b7691c7d0b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 Mar 2016 13:19:37 -0400 Subject: [PATCH 03/21] thread the DepGraph to session/crate-store This is a [breaking-change] for plugin authors. You must now create a dep-graph earlier. --- src/librustc/dep_graph/dep_node.rs | 6 ------ src/librustc/hir/map/mod.rs | 4 ++-- src/librustc/middle/cstore.rs | 1 - src/librustc/session/config.rs | 14 +++++++++----- src/librustc/session/mod.rs | 22 +++++++++++++++++----- src/librustc_driver/driver.rs | 9 ++++----- src/librustc_driver/lib.rs | 15 +++++++++++---- src/librustc_driver/pretty.rs | 2 +- src/librustc_driver/test.rs | 11 ++++++----- src/librustc_metadata/cstore.rs | 6 +++++- src/librustdoc/core.rs | 12 ++++++------ src/librustdoc/test.rs | 11 ++++++++--- src/test/run-make/execution-engine/test.rs | 12 ++++++++---- src/test/run-make/issue-19371/foo.rs | 6 ++++-- 14 files changed, 81 insertions(+), 50 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index b81aa5822369..3e43c8e2c935 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -32,12 +32,6 @@ pub enum DepNode { // Represents the HIR node with the given node-id Hir(D), - // Represents the meta-data for a node. For local def-ids, this is - // created by trans. For remote def-ids, we add a read of this - // node each time we pull the information for an item out of the - // crate store. - MetaData(D), - // Represents different phases in the compiler. CrateReader, CollectLanguageItems, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index c0bbccad5f20..e3976482dca8 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -160,10 +160,10 @@ pub struct Forest { } impl Forest { - pub fn new(krate: Crate, dep_graph: DepGraph) -> Forest { + pub fn new(krate: Crate, dep_graph: &DepGraph) -> Forest { Forest { krate: krate, - dep_graph: dep_graph, + dep_graph: dep_graph.clone(), inlined_items: TypedArena::new() } } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 85c31774cc44..17c6442c019b 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -34,7 +34,6 @@ use session::Session; use session::config::PanicStrategy; use session::search_paths::PathKind; use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; -use std::any::Any; use std::cell::RefCell; use std::rc::Rc; use std::path::PathBuf; diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 7d1d5dba3983..7bb96c5ab2b4 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1420,6 +1420,7 @@ impl fmt::Display for CrateType { #[cfg(test)] mod tests { + use dep_graph::DepGraph; use middle::cstore::DummyCrateStore; use session::config::{build_configuration, build_session_options}; use session::build_session; @@ -1439,6 +1440,7 @@ mod tests { // When the user supplies --test we should implicitly supply --cfg test #[test] fn test_switch_implies_cfg_test() { + let dep_graph = DepGraph::new(false); let matches = &match getopts(&["--test".to_string()], &optgroups()) { Ok(m) => m, @@ -1446,7 +1448,7 @@ mod tests { }; let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(matches); - let sess = build_session(sessopts, None, registry, Rc::new(DummyCrateStore)); + let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); let cfg = build_configuration(&sess); assert!((attr::contains_name(&cfg[..], "test"))); } @@ -1455,6 +1457,7 @@ mod tests { // another --cfg test #[test] fn test_switch_implies_cfg_test_unless_cfg_test() { + let dep_graph = DepGraph::new(false); let matches = &match getopts(&["--test".to_string(), "--cfg=test".to_string()], &optgroups()) { @@ -1465,7 +1468,7 @@ mod tests { }; let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(matches); - let sess = build_session(sessopts, None, registry, + let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); let cfg = build_configuration(&sess); let mut test_items = cfg.iter().filter(|m| m.name() == "test"); @@ -1475,13 +1478,14 @@ mod tests { #[test] fn test_can_print_warnings() { + let dep_graph = DepGraph::new(false); { let matches = getopts(&[ "-Awarnings".to_string() ], &optgroups()).unwrap(); let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(&matches); - let sess = build_session(sessopts, None, registry, + let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); assert!(!sess.diagnostic().can_emit_warnings); } @@ -1493,7 +1497,7 @@ mod tests { ], &optgroups()).unwrap(); let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(&matches); - let sess = build_session(sessopts, None, registry, + let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); assert!(sess.diagnostic().can_emit_warnings); } @@ -1504,7 +1508,7 @@ mod tests { ], &optgroups()).unwrap(); let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(&matches); - let sess = build_session(sessopts, None, registry, + let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); assert!(sess.diagnostic().can_emit_warnings); } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1bea01c4849e..61d6acfe061f 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use dep_graph::DepGraph; use lint; use middle::cstore::CrateStore; use middle::dependency_format; @@ -49,6 +50,7 @@ pub mod search_paths; // Represents the data associated with a compilation // session for a single crate. pub struct Session { + pub dep_graph: DepGraph, pub target: config::Config, pub host: Target, pub opts: config::Options, @@ -408,18 +410,21 @@ fn split_msg_into_multilines(msg: &str) -> Option { } pub fn build_session(sopts: config::Options, + dep_graph: &DepGraph, local_crate_source_file: Option, registry: diagnostics::registry::Registry, cstore: Rc CrateStore<'a>>) -> Session { build_session_with_codemap(sopts, - local_crate_source_file, - registry, - cstore, - Rc::new(codemap::CodeMap::new())) + dep_graph, + local_crate_source_file, + registry, + cstore, + Rc::new(codemap::CodeMap::new())) } pub fn build_session_with_codemap(sopts: config::Options, + dep_graph: &DepGraph, local_crate_source_file: Option, registry: diagnostics::registry::Registry, cstore: Rc CrateStore<'a>>, @@ -450,10 +455,16 @@ pub fn build_session_with_codemap(sopts: config::Options, treat_err_as_bug, emitter); - build_session_(sopts, local_crate_source_file, diagnostic_handler, codemap, cstore) + build_session_(sopts, + dep_graph, + local_crate_source_file, + diagnostic_handler, + codemap, + cstore) } pub fn build_session_(sopts: config::Options, + dep_graph: &DepGraph, local_crate_source_file: Option, span_diagnostic: errors::Handler, codemap: Rc, @@ -482,6 +493,7 @@ pub fn build_session_(sopts: config::Options, ); let sess = Session { + dep_graph: dep_graph.clone(), target: target_cfg, host: host, opts: sopts, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 46356add8c68..da6af9140929 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -152,7 +152,6 @@ pub fn compile_input(sess: &Session, Ok(())); let expanded_crate = assign_node_ids(sess, expanded_crate); - let dep_graph = DepGraph::new(sess.opts.build_dep_graph()); // Collect defintions for def ids. let mut defs = time(sess.time_passes(), @@ -161,15 +160,15 @@ pub fn compile_input(sess: &Session, time(sess.time_passes(), "external crate/lib resolution", - || read_local_crates(sess, &cstore, &defs, &expanded_crate, &id, &dep_graph)); + || read_local_crates(sess, &cstore, &defs, &expanded_crate, &id, &sess.dep_graph)); time(sess.time_passes(), "early lint checks", || lint::check_ast_crate(sess, &expanded_crate)); let (analysis, resolutions, mut hir_forest) = { - lower_and_resolve(sess, &id, &mut defs, &expanded_crate, dep_graph, - control.make_glob_map) + lower_and_resolve(sess, &id, &mut defs, &expanded_crate, + &sess.dep_graph, control.make_glob_map) }; // Discard MTWT tables that aren't required past lowering to HIR. @@ -805,7 +804,7 @@ pub fn lower_and_resolve<'a>(sess: &Session, id: &'a str, defs: &mut hir_map::Definitions, krate: &ast::Crate, - dep_graph: DepGraph, + dep_graph: &DepGraph, make_glob_map: resolve::MakeGlobMap) -> (ty::CrateAnalysis<'a>, Resolutions, hir_map::Forest) { resolve::with_resolver(sess, defs, make_glob_map, |mut resolver| { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 2a4b30e016f2..06133c508d9f 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -67,6 +67,7 @@ use pretty::{PpMode, UserIdentifiedItem}; use rustc_resolve as resolve; use rustc_save_analysis as save; use rustc_trans::back::link; +use rustc::dep_graph::DepGraph; use rustc::session::{self, config, Session, build_session, CompileResult}; use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType}; use rustc::session::config::{get_unstable_features_setting, nightly_options}; @@ -196,9 +197,11 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], }, }; - let cstore = Rc::new(CStore::new(token::get_ident_interner())); + let dep_graph = DepGraph::new(sopts.build_dep_graph()); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); let codemap = Rc::new(CodeMap::with_file_loader(loader)); let sess = session::build_session_with_codemap(sopts, + &dep_graph, input_file_path, descriptions, cstore.clone(), @@ -425,9 +428,13 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { describe_lints(&ls, false); return None; } - let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = build_session(sopts.clone(), None, descriptions.clone(), - cstore.clone()); + let dep_graph = DepGraph::new(sopts.build_dep_graph()); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); + let sess = build_session(sopts.clone(), + &dep_graph, + None, + descriptions.clone(), + cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let should_stop = RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile); if should_stop == Compilation::Stop { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 9aae9f04c92c..8c84e561e317 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -18,10 +18,10 @@ use self::NodesMatchingUII::*; use abort_on_err; use driver::{self, Resolutions}; -use rustc::dep_graph::DepGraph; use rustc::ty::{self, TyCtxt}; use rustc::cfg; use rustc::cfg::graphviz::LabelledCFG; +use rustc::dep_graph::DepGraph; use rustc::session::Session; use rustc::session::config::Input; use rustc_borrowck as borrowck; diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index bbda1965c7fa..e0d693c42309 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -104,8 +104,10 @@ fn test_env(source_string: &str, options.unstable_features = UnstableFeatures::Allow; let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = session::build_session_(options, None, diagnostic_handler, + let dep_graph = DepGraph::new(false); + let _ignore = dep_graph.in_ignore(); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); + let sess = session::build_session_(options, &dep_graph, None, diagnostic_handler, Rc::new(CodeMap::new()), cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let krate_config = Vec::new(); @@ -117,15 +119,14 @@ fn test_env(source_string: &str, let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "test", None) .expect("phase 2 aborted"); - let dep_graph = DepGraph::new(false); let krate = driver::assign_node_ids(&sess, krate); let mut defs = hir_map::collect_definitions(&krate); read_local_crates(&sess, &cstore, &defs, &krate, "test_crate", &dep_graph); let _ignore = dep_graph.in_ignore(); let (_, resolutions, mut hir_forest) = { - driver::lower_and_resolve(&sess, "test-crate", &mut defs, &krate, dep_graph.clone(), - MakeGlobMap::No) + driver::lower_and_resolve(&sess, "test-crate", &mut defs, &krate, + &sess.dep_graph, MakeGlobMap::No) }; let arenas = ty::CtxtArenas::new(); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 04b6e1c42b98..940688f55074 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -20,6 +20,7 @@ use decoder; use index; use loader; +use rustc::dep_graph::DepGraph; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; use rustc::middle::cstore::{ExternCrate}; @@ -86,6 +87,7 @@ pub struct crate_metadata { } pub struct CStore { + _dep_graph: DepGraph, metas: RefCell>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: RefCell>, @@ -98,8 +100,10 @@ pub struct CStore { } impl CStore { - pub fn new(intr: Rc) -> CStore { + pub fn new(dep_graph: &DepGraph, + intr: Rc) -> CStore { CStore { + _dep_graph: dep_graph.clone(), metas: RefCell::new(FnvHashMap()), extern_mod_crate_map: RefCell::new(FnvHashMap()), used_crate_sources: RefCell::new(Vec::new()), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 6d45980b45da..4ae869c32597 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -134,8 +134,10 @@ pub fn run_core(search_paths: SearchPaths, false, codemap.clone()); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = session::build_session_(sessopts, cpath, diagnostic_handler, + let dep_graph = DepGraph::new(false); + let _ignore = dep_graph.in_ignore(); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); + let sess = session::build_session_(sessopts, &dep_graph, cpath, diagnostic_handler, codemap, cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); @@ -151,15 +153,14 @@ pub fn run_core(search_paths: SearchPaths, .expect("phase_2_configure_and_expand aborted in rustdoc!"); let krate = driver::assign_node_ids(&sess, krate); - let dep_graph = DepGraph::new(false); let mut defs = hir_map::collect_definitions(&krate); read_local_crates(&sess, &cstore, &defs, &krate, &name, &dep_graph); // Lower ast -> hir and resolve. let (analysis, resolutions, mut hir_forest) = { - driver::lower_and_resolve(&sess, &name, &mut defs, &krate, dep_graph, - resolve::MakeGlobMap::No) + driver::lower_and_resolve(&sess, &name, &mut defs, &krate, + &sess.dep_graph, resolve::MakeGlobMap::No) }; let arenas = ty::CtxtArenas::new(); @@ -177,7 +178,6 @@ pub fn run_core(search_paths: SearchPaths, return None } - let _ignore = tcx.dep_graph.in_ignore(); let ty::CrateAnalysis { access_levels, .. } = analysis; // Convert from a NodeId set to a DefId set since we don't always have easy access diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index e4fbdba77a44..bec18d2cc63f 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -79,8 +79,11 @@ pub fn run(input: &str, false, codemap.clone()); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); + let dep_graph = DepGraph::new(false); + let _ignore = dep_graph.in_ignore(); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); let sess = session::build_session_(sessopts, + &dep_graph, Some(input_path.clone()), diagnostic_handler, codemap, @@ -103,7 +106,7 @@ pub fn run(input: &str, let opts = scrape_test_config(&krate); let _ignore = dep_graph.in_ignore(); - let mut forest = hir_map::Forest::new(krate, dep_graph.clone()); + let mut forest = hir_map::Forest::new(krate, &dep_graph); let map = hir_map::map_crate(&mut forest, defs); let ctx = core::DocContext { @@ -238,8 +241,10 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, // Compile the code let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); + let dep_graph = DepGraph::new(false); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); let sess = session::build_session_(sessopts, + &dep_graph, None, diagnostic_handler, codemap, diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index 0ad113b8d8b3..0e84a0f52218 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -223,8 +223,12 @@ fn compile_program(input: &str, sysroot: PathBuf) let handle = thread.spawn(move || { let opts = build_exec_options(sysroot); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = build_session(opts, None, Registry::new(&rustc::DIAGNOSTICS), + let dep_graph = DepGraph::new(opts.build_dep_graph()); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); + let sess = build_session(opts, + &dep_graph, + None, + Registry::new(&rustc::DIAGNOSTICS), cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); @@ -237,12 +241,12 @@ fn compile_program(input: &str, sysroot: PathBuf) let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None) .expect("phase_2 returned `None`"); - let dep_graph = DepGraph::new(sess.opts.build_dep_graph()); let krate = driver::assign_node_ids(&sess, krate); let mut defs = ast_map::collect_definitions(&krate); read_local_crates(&sess, &cstore, &defs, &krate, &id, &dep_graph); let (analysis, resolutions, mut hir_forest) = { - driver::lower_and_resolve(&sess, &id, &mut defs, &krate, dep_graph, MakeGlobMap::No) + driver::lower_and_resolve(&sess, &id, &mut defs, &krate, + &sess.dep_graph, MakeGlobMap::No) }; let arenas = ty::CtxtArenas::new(); diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 80c06ca3274f..41d250eadec4 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -16,6 +16,7 @@ extern crate rustc_lint; extern crate rustc_metadata; extern crate syntax; +use rustc::dep_graph::DepGraph; use rustc::session::{build_session, Session}; use rustc::session::config::{basic_options, build_configuration, Input, OutputType}; use rustc_driver::driver::{compile_input, CompileController, anon_src}; @@ -54,8 +55,9 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { opts.maybe_sysroot = Some(sysroot); let descriptions = Registry::new(&rustc::DIAGNOSTICS); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = build_session(opts, None, descriptions, cstore.clone()); + let dep_graph = DepGraph::new(opts.build_dep_graph()); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); + 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) } From 7734308f895eb415c92365fab883ecbb5419fb27 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 10 May 2016 20:50:00 -0400 Subject: [PATCH 04/21] ignore dep-graph in resolve and lower_crate This got removed at some point, it seems. --- src/librustc/hir/lowering.rs | 11 ++++++++++- src/librustc_driver/driver.rs | 2 +- src/librustc_resolve/lib.rs | 1 + src/librustdoc/test.rs | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 67ea7951de71..ba655b35eda1 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -45,6 +45,7 @@ use hir::map::Definitions; use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId}; use hir::def::{Def, PathResolution}; +use session::Session; use std::collections::BTreeMap; use std::iter; @@ -97,8 +98,16 @@ impl Resolver for DummyResolver { } } -pub fn lower_crate(krate: &Crate, id_assigner: &NodeIdAssigner, resolver: &mut Resolver) +pub fn lower_crate(sess: &Session, + krate: &Crate, + id_assigner: &NodeIdAssigner, + resolver: &mut Resolver) -> hir::Crate { + // We're constructing the HIR here; we don't care what we will + // read, since we haven't even constructed the *input* to + // incr. comp. yet. + let _ignore = sess.dep_graph.in_ignore(); + LoweringContext { crate_root: if std_inject::no_core(krate) { None diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index da6af9140929..1d60c2eb4378 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -814,7 +814,7 @@ pub fn lower_and_resolve<'a>(sess: &Session, // Lower ast -> hir. let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || { - hir_map::Forest::new(lower_crate(krate, sess, &mut resolver), dep_graph) + hir_map::Forest::new(lower_crate(sess, krate, sess, &mut resolver), dep_graph) }); (ty::CrateAnalysis { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 016dff5f0053..61ed88ec173d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3624,6 +3624,7 @@ pub fn resolve_crate<'a, 'b>(resolver: &'b mut Resolver<'a>, krate: &'b Crate) { // reflects not just its contents but the results of name // resolution on those contents. Hopefully we'll push this back at // some point. + let _ignore = resolver.session.dep_graph.in_ignore(); resolver.build_reduced_graph(krate); resolve_imports::resolve_imports(resolver); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index bec18d2cc63f..2754f77444c6 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -101,7 +101,7 @@ pub fn run(input: &str, let defs = hir_map::collect_definitions(&krate); let mut dummy_resolver = DummyResolver; - let krate = lower_crate(&krate, &sess, &mut dummy_resolver); + let krate = lower_crate(&sess, &krate, &sess, &mut dummy_resolver); let opts = scrape_test_config(&krate); From 5bcdf4c1928bb07beaea0c3b143f8ff2a1b73922 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 22 Apr 2016 15:47:14 -0400 Subject: [PATCH 05/21] add a MetaData node and trigger reads from it Conflicts: src/librustc_metadata/csearch.rs --- src/librustc/dep_graph/dep_node.rs | 5 +++ src/librustc_metadata/csearch.rs | 55 ++++++++++++++++++++++++++---- src/librustc_metadata/cstore.rs | 4 +-- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 3e43c8e2c935..f2c9d0b12201 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -32,6 +32,10 @@ pub enum DepNode { // Represents the HIR node with the given node-id Hir(D), + // Represents the metadata for a given HIR node, typically found + // in an extern crate. + MetaData(D), + // Represents different phases in the compiler. CrateReader, CollectLanguageItems, @@ -175,6 +179,7 @@ impl DepNode { TransCrate => Some(TransCrate), TransWriteMetadata => Some(TransWriteMetadata), Hir(ref d) => op(d).map(Hir), + MetaData(ref d) => op(d).map(MetaData), CollectItem(ref d) => op(d).map(CollectItem), CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl), CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck), diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 8d464099783a..ac094676ae8a 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -20,6 +20,7 @@ use middle::lang_items; use rustc::ty::{self, Ty, TyCtxt, VariantKind}; use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; +use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::mir::repr::Mir; use rustc::mir::mir_map::MirMap; @@ -37,19 +38,20 @@ use rustc_back::target::Target; use rustc::hir; impl<'tcx> CrateStore<'tcx> for cstore::CStore { - fn stability(&self, def: DefId) -> Option - { + fn stability(&self, def: DefId) -> Option { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_stability(&cdata, def.index) } - fn deprecation(&self, def: DefId) -> Option - { + fn deprecation(&self, def: DefId) -> Option { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_deprecation(&cdata, def.index) } fn visibility(&self, def: DefId) -> ty::Visibility { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_visibility(&cdata, def.index) } @@ -57,23 +59,26 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { assert!(!def_id.is_local()); + self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); decoder::closure_kind(&cdata, def_id.index) } - fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> - { + fn closure_ty(&self, tcx: &TyCtxt<'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> { assert!(!def_id.is_local()); + self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); decoder::closure_ty(&cdata, def_id.index, tcx) } fn item_variances(&self, def: DefId) -> ty::ItemVariances { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_item_variances(&cdata, def.index) } fn repr_attrs(&self, def: DefId) -> Vec { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_repr_attrs(&cdata, def.index) } @@ -81,6 +86,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TypeScheme<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_type(&cdata, def.index, tcx) } @@ -88,6 +94,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_predicates(&cdata, def.index, tcx) } @@ -95,41 +102,48 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_super_predicates(&cdata, def.index, tcx) } fn item_attrs(&self, def_id: DefId) -> Vec { + self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); decoder::get_item_attrs(&cdata, def_id.index) } fn item_symbol(&self, def: DefId) -> String { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_symbol(&cdata, def.index) } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_trait_def(&cdata, def.index, tcx) } fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_adt_def(&self.intr, &cdata, def.index, tcx) } fn method_arg_names(&self, did: DefId) -> Vec { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::get_method_arg_names(&cdata, did.index) } fn item_name(&self, def: DefId) -> ast::Name { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_item_name(&self.intr, &cdata, def.index) } @@ -137,6 +151,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec { + self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; let cdata = self.get_crate_data(def_id.krate); decoder::each_inherent_implementation_for_type(&cdata, def_id.index, @@ -146,6 +161,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn implementations_of_trait(&self, def_id: DefId) -> Vec { + self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; self.iter_crate_data(|_, cdata| { decoder::each_implementation_for_trait(cdata, def_id, &mut |iid| { @@ -158,6 +174,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn provided_trait_methods<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Vec>> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_provided_trait_methods(self.intr.clone(), &cdata, def.index, tcx) } @@ -165,18 +182,21 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn trait_item_def_ids(&self, def: DefId) -> Vec { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_trait_item_def_ids(&cdata, def.index) } fn impl_items(&self, impl_def_id: DefId) -> Vec { + self.dep_graph.read(DepNode::MetaData(impl_def_id)); let cdata = self.get_crate_data(impl_def_id.krate); decoder::get_impl_items(&cdata, impl_def_id.index) } fn impl_polarity(&self, def: DefId) -> Option { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_impl_polarity(&cdata, def.index) } @@ -184,6 +204,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_impl_trait(&cdata, def.index, tcx) } @@ -191,6 +212,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn custom_coerce_unsized_kind(&self, def: DefId) -> Option { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_custom_coerce_unsized_kind(&cdata, def.index) } @@ -198,17 +220,20 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { // FIXME: killme fn associated_consts<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Vec>> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_associated_consts(self.intr.clone(), &cdata, def.index, tcx) } fn impl_parent(&self, impl_def: DefId) -> Option { + self.dep_graph.read(DepNode::MetaData(impl_def)); let cdata = self.get_crate_data(impl_def.krate); decoder::get_parent_impl(&*cdata, impl_def.index) } fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option { + self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); decoder::get_trait_of_item(&cdata, def_id.index, tcx) } @@ -216,6 +241,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_impl_or_trait_item( self.intr.clone(), @@ -226,34 +252,40 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn is_const_fn(&self, did: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::is_const_fn(&cdata, did.index) } fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(trait_def_id)); let cdata = self.get_crate_data(trait_def_id.krate); decoder::is_defaulted_trait(&cdata, trait_def_id.index) } fn is_impl(&self, did: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::is_impl(&cdata, did.index) } fn is_default_impl(&self, impl_did: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(impl_did)); let cdata = self.get_crate_data(impl_did.krate); decoder::is_default_impl(&cdata, impl_did.index) } fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::is_extern_item(&cdata, did.index, tcx) } fn is_static_method(&self, def: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::is_static_method(&cdata, def.index) } @@ -264,6 +296,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { } fn is_typedef(&self, did: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::is_typedef(&cdata, did.index) } @@ -379,40 +412,47 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { /// parent `DefId` as well as some idea of what kind of data the /// `DefId` refers to. fn def_key(&self, def: DefId) -> hir_map::DefKey { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::def_key(&cdata, def.index) } fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::def_path(&cdata, def.index) } fn variant_kind(&self, def_id: DefId) -> Option { + self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); decoder::get_variant_kind(&cdata, def_id.index) } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { + self.dep_graph.read(DepNode::MetaData(struct_def_id)); let cdata = self.get_crate_data(struct_def_id.krate); decoder::get_struct_ctor_def_id(&cdata, struct_def_id.index) } fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::get_tuple_struct_definition_if_ctor(&cdata, did.index) } fn struct_field_names(&self, def: DefId) -> Vec { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_struct_field_names(&self.intr, &cdata, def.index) } fn item_children(&self, def_id: DefId) -> Vec { + self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; let crate_data = self.get_crate_data(def_id.krate); let get_crate_data = |cnum| self.get_crate_data(cnum); @@ -445,17 +485,20 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> FoundAst<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::maybe_get_item_ast(&cdata, tcx, def.index) } fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::maybe_get_item_mir(&cdata, tcx, def.index) } fn is_item_mir_available(&self, def: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::is_item_mir_available(&cdata, def.index) } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 940688f55074..d3c4c5b02920 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -87,7 +87,7 @@ pub struct crate_metadata { } pub struct CStore { - _dep_graph: DepGraph, + pub dep_graph: DepGraph, metas: RefCell>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: RefCell>, @@ -103,7 +103,7 @@ impl CStore { pub fn new(dep_graph: &DepGraph, intr: Rc) -> CStore { CStore { - _dep_graph: dep_graph.clone(), + dep_graph: dep_graph.clone(), metas: RefCell::new(FnvHashMap()), extern_mod_crate_map: RefCell::new(FnvHashMap()), used_crate_sources: RefCell::new(Vec::new()), From ef902a211be7c699daefafb515ef11d9d929687f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 6 Apr 2016 14:49:50 -0400 Subject: [PATCH 06/21] when encoding, push MetaData(foo) task on stack This lets us determine what was used to construct the metadata. Conflicts: src/librustc_metadata/encoder.rs --- src/librustc/dep_graph/mod.rs | 1 + src/librustc_metadata/csearch.rs | 2 +- src/librustc_metadata/encoder.rs | 120 +++++++++++++++++-------------- src/librustc_metadata/index.rs | 2 +- 4 files changed, 71 insertions(+), 54 deletions(-) diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 49481dcb7967..9c1bc3324dbb 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -22,3 +22,4 @@ pub use self::dep_node::DepNode; pub use self::graph::DepGraph; pub use self::query::DepGraphQuery; pub use self::visit::visit_all_items_in_krate; +pub use self::raii::DepTask; diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index ac094676ae8a..54e078a16f0a 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -64,7 +64,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::closure_kind(&cdata, def_id.index) } - fn closure_ty(&self, tcx: &TyCtxt<'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> { + fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> { assert!(!def_id.is_local()); self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 662942a5bdc1..8a16a4b4a634 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -25,6 +25,7 @@ use middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls}; use rustc::hir::def; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; +use rustc::dep_graph::{DepGraph, DepNode, DepTask}; use rustc::ty::subst; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; @@ -76,15 +77,23 @@ impl<'a, 'tcx> EncodeContext<'a,'tcx> { #[derive(PartialEq, Eq, Hash)] pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } -struct CrateIndex<'tcx> { +struct CrateIndex<'a, 'tcx> { + dep_graph: &'a DepGraph, items: IndexData, xrefs: FnvHashMap, u32>, // sequentially-assigned } -impl<'tcx> CrateIndex<'tcx> { - fn record(&mut self, id: DefId, rbml_w: &mut Encoder) { +impl<'a, 'tcx> CrateIndex<'a, 'tcx> { + /// Records that `id` is being emitted at the current offset. + /// This data is later used to construct the item index in the + /// metadata so we can quickly find the data for a given item. + /// + /// Returns a dep-graph task that you should keep live as long as + /// the data for this item is being emitted. + fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> { let position = rbml_w.mark_stable_position(); self.items.record(id, position); + self.dep_graph.in_task(DepNode::MetaData(id)) } fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { @@ -154,7 +163,7 @@ fn encode_item_variances(rbml_w: &mut Encoder, fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, id: NodeId) { encode_bounds_and_type(rbml_w, ecx, @@ -165,7 +174,7 @@ fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, scheme: &ty::TypeScheme<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { encode_generics(rbml_w, ecx, index, @@ -248,7 +257,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, did: DefId, vis: &hir::Visibility, - index: &mut CrateIndex<'tcx>) { + index: &mut CrateIndex<'a, 'tcx>) { debug!("encode_enum_variant_info(did={:?})", did); let repr_hints = ecx.tcx.lookup_repr_hints(did); let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0)); @@ -266,7 +275,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } } - index.record(vid, rbml_w); + let _task = index.record(vid, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, vid); encode_family(rbml_w, match variant.kind() { @@ -471,11 +480,11 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, field: ty::FieldDef<'tcx>, - index: &mut CrateIndex<'tcx>) { + index: &mut CrateIndex<'a, 'tcx>) { let nm = field.name; let id = ecx.local_id(field.did); - index.record(field.did, rbml_w); + let _task = index.record(field.did, rbml_w); rbml_w.start_tag(tag_items_data_item); debug!("encode_field: encoding {} {}", nm, id); encode_struct_field_family(rbml_w, field.vis); @@ -495,12 +504,12 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, name: Name, struct_def: &hir::VariantData, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, struct_id: NodeId) { let ctor_id = struct_def.id(); let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); - index.record(ctor_def_id, rbml_w); + let _task = index.record(ctor_def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, ctor_def_id); encode_family(rbml_w, match *struct_def { @@ -531,7 +540,7 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, generics: &ty::Generics<'tcx>, predicates: &ty::GenericPredicates<'tcx>, tag: usize) @@ -576,7 +585,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder, _ecx: &EncodeContext<'a,'tcx>, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, predicates: &ty::GenericPredicates<'tcx>) { for (space, _, predicate) in predicates.predicates.iter_enumerated() { @@ -593,7 +602,7 @@ fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder, fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a,'tcx>, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, predicates: &ty::GenericPredicates<'tcx>, tag: usize) { @@ -604,7 +613,7 @@ fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, method_ty: &ty::Method<'tcx>) { encode_def_id_and_key(ecx, rbml_w, method_ty.def_id); encode_name(rbml_w, method_ty.name); @@ -623,7 +632,7 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, associated_const: &ty::AssociatedConst, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { @@ -631,7 +640,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, associated_const.def_id, associated_const.name); - index.record(associated_const.def_id, rbml_w); + let _task = index.record(associated_const.def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); @@ -665,7 +674,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, m: &ty::Method<'tcx>, is_default_impl: bool, parent_id: NodeId, @@ -673,7 +682,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, debug!("encode_info_for_method: {:?} {:?}", m.def_id, m.name); - index.record(m.def_id, rbml_w); + let _task = index.record(m.def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_method_ty_fields(ecx, rbml_w, index, m); @@ -717,7 +726,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, associated_type: &ty::AssociatedType<'tcx>, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { @@ -725,7 +734,7 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, associated_type.def_id, associated_type.name); - index.record(associated_type.def_id, rbml_w); + let _task = index.record(associated_type.def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); @@ -863,7 +872,7 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, item: &hir::Item, - index: &mut CrateIndex<'tcx>) { + index: &mut CrateIndex<'a, 'tcx>) { let tcx = ecx.tcx; debug!("encoding info for item at {}", @@ -871,12 +880,15 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let vis = &item.vis; let def_id = ecx.tcx.map.local_def_id(item.id); - let stab = tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)); - let depr = tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id)); + + let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || { + (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)), + tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id))) + }); match item.node { hir::ItemStatic(_, m, _) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); if m == hir::MutMutable { @@ -894,7 +906,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemConst(_, _) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'C'); @@ -909,7 +921,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, FN_FAMILY); @@ -933,7 +945,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemMod(ref m) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); encode_info_for_mod(ecx, rbml_w, m, @@ -943,7 +955,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, &item.vis); } hir::ItemForeignMod(ref fm) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'n'); @@ -960,7 +972,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemTy(..) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'y'); @@ -972,7 +984,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemEnum(ref enum_definition, _) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); @@ -1003,12 +1015,12 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, index); } hir::ItemStruct(ref struct_def, _) => { + /* Index the class*/ + let _task = index.record(def_id, rbml_w); + let def = ecx.tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); - /* Index the class*/ - index.record(def_id, rbml_w); - /* Now, make an item for the class itself */ rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); @@ -1056,7 +1068,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } } hir::ItemDefaultImpl(unsafety, _) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'd'); @@ -1068,12 +1080,13 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => { + let _task = index.record(def_id, rbml_w); + // We need to encode information about the default methods we // have inherited, so we drive this based on the impl structure. let impl_items = tcx.impl_items.borrow(); let items = impl_items.get(&def_id).unwrap(); - index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'i'); @@ -1170,7 +1183,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } } hir::ItemTrait(_, _, _, ref ms) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'I'); @@ -1225,7 +1238,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, for (i, &item_def_id) in r.iter().enumerate() { assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); - index.record(item_def_id.def_id(), rbml_w); + let _task = index.record(item_def_id.def_id(), rbml_w); rbml_w.start_tag(tag_items_data_item); encode_parent_item(rbml_w, def_id); @@ -1336,12 +1349,12 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, nitem: &hir::ForeignItem, - index: &mut CrateIndex<'tcx>) { + index: &mut CrateIndex<'a, 'tcx>) { debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id)); let def_id = ecx.tcx.map.local_def_id(nitem.id); let abi = ecx.tcx.map.get_foreign_abi(nitem.id); - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_visibility(rbml_w, &nitem.vis); @@ -1390,7 +1403,7 @@ fn my_visit_expr(expr: &hir::Expr, hir::ExprClosure(..) => { let def_id = ecx.tcx.map.local_def_id(expr.id); - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); @@ -1414,8 +1427,8 @@ fn my_visit_expr(expr: &hir::Expr, struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { rbml_w_for_visit_item: &'a mut Encoder<'b>, - ecx: &'a EncodeContext<'c,'tcx>, - index: &'a mut CrateIndex<'tcx>, + ecx: &'a EncodeContext<'c, 'tcx>, + index: &'a mut CrateIndex<'c, 'tcx>, } impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> { @@ -1435,23 +1448,26 @@ impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> { fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder) - -> CrateIndex<'tcx> { + -> CrateIndex<'a, 'tcx> { let krate = ecx.tcx.map.krate(); let mut index = CrateIndex { + dep_graph: &ecx.tcx.dep_graph, items: IndexData::new(ecx.tcx.map.num_local_def_ids()), xrefs: FnvHashMap() }; rbml_w.start_tag(tag_items_data); - index.record(DefId::local(CRATE_DEF_INDEX), rbml_w); - encode_info_for_mod(ecx, - rbml_w, - &krate.module, - &[], - CRATE_NODE_ID, - syntax::parse::token::intern(&ecx.link_meta.crate_name), - &hir::Public); + { + let _task = index.record(DefId::local(CRATE_DEF_INDEX), rbml_w); + encode_info_for_mod(ecx, + rbml_w, + &krate.module, + &[], + CRATE_NODE_ID, + syntax::parse::token::intern(&ecx.link_meta.crate_name), + &hir::Public); + } krate.visit_all_items(&mut EncodeVisitor { index: &mut index, diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index 9c066f9f5f1f..b850073462f5 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -75,7 +75,7 @@ impl IndexData { pub fn record(&mut self, def_id: DefId, position: u64) { assert!(def_id.is_local()); - self.record_index(def_id.index, position) + self.record_index(def_id.index, position); } pub fn record_index(&mut self, item: DefIndex, position: u64) { From bc02a54d12f8b03506ae8eda50a05784cf04b63f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 6 Apr 2016 12:01:40 -0400 Subject: [PATCH 07/21] rename the dep-graph file to include crate ident This way, multiple compilations can share the same work directory. --- src/librustc_incremental/persist/util.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs index 8ebcbc0466f3..754292ba3830 100644 --- a/src/librustc_incremental/persist/util.rs +++ b/src/librustc_incremental/persist/util.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc::middle::cstore::LOCAL_CRATE; use rustc::ty::TyCtxt; use std::fs; @@ -28,7 +29,12 @@ pub fn dep_graph_path(tcx: TyCtxt) -> Option { } } - Some(incr_dir.join("dep_graph.rbml")) + let crate_name = tcx.crate_name(LOCAL_CRATE); + let crate_disambiguator = tcx.crate_disambiguator(LOCAL_CRATE); + let file_name = format!("dep-graph-{}-{}.bin", + crate_name, + crate_disambiguator); + Some(incr_dir.join(file_name)) }) } From f89041bbe3da48d98c1512b39c819ed42cff4e78 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 6 Apr 2016 17:28:59 -0400 Subject: [PATCH 08/21] identify inputs of `MetaData(X)` nodes Generate a second hash file that contains the metadata for an X node. --- src/librustc/cfg/mod.rs | 2 +- src/librustc/dep_graph/query.rs | 21 ++- src/librustc/infer/region_inference/mod.rs | 4 +- src/librustc_data_structures/graph/mod.rs | 14 +- src/librustc_incremental/assert_dep_graph.rs | 2 +- src/librustc_incremental/persist/data.rs | 34 +++- src/librustc_incremental/persist/load.rs | 17 +- src/librustc_incremental/persist/save.rs | 172 +++++++++++++------ src/librustc_incremental/persist/util.rs | 35 +++- src/librustc_trans/base.rs | 3 +- 10 files changed, 221 insertions(+), 83 deletions(-) diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index 617e2ed2f1ae..d06f51073df0 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -64,7 +64,7 @@ impl CFG { } pub fn node_is_reachable(&self, id: ast::NodeId) -> bool { - self.graph.depth_traverse(self.entry) + self.graph.depth_traverse(self.entry, graph::OUTGOING) .any(|idx| self.graph.node_data(idx).id() == id) } } diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs index acc6660da6e8..93248edb197c 100644 --- a/src/librustc/dep_graph/query.rs +++ b/src/librustc/dep_graph/query.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc_data_structures::fnv::FnvHashMap; -use rustc_data_structures::graph::{Graph, NodeIndex}; +use rustc_data_structures::graph::{Direction, INCOMING, Graph, NodeIndex, OUTGOING}; use std::fmt::Debug; use std::hash::Hash; @@ -63,11 +63,9 @@ impl DepGraphQuery { .collect() } - /// All nodes reachable from `node`. In other words, things that - /// will have to be recomputed if `node` changes. - pub fn transitive_dependents(&self, node: DepNode) -> Vec> { + fn reachable_nodes(&self, node: DepNode, direction: Direction) -> Vec> { if let Some(&index) = self.indices.get(&node) { - self.graph.depth_traverse(index) + self.graph.depth_traverse(index, direction) .map(|s| self.graph.node_data(s).clone()) .collect() } else { @@ -75,8 +73,19 @@ impl DepGraphQuery { } } + /// All nodes reachable from `node`. In other words, things that + /// will have to be recomputed if `node` changes. + pub fn transitive_successors(&self, node: DepNode) -> Vec> { + self.reachable_nodes(node, OUTGOING) + } + + /// All nodes that can reach `node`. + pub fn transitive_predecessors(&self, node: DepNode) -> Vec> { + self.reachable_nodes(node, INCOMING) + } + /// Just the outgoing edges from `node`. - pub fn immediate_dependents(&self, node: DepNode) -> Vec> { + pub fn immediate_successors(&self, node: DepNode) -> Vec> { if let Some(&index) = self.indices.get(&node) { self.graph.successor_nodes(index) .map(|s| self.graph.node_data(s).clone()) diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 9d2d52015e39..5312d0305255 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -20,7 +20,7 @@ pub use self::VarValue::*; use super::{RegionVariableOrigin, SubregionOrigin, MiscVariable}; use super::unify_key; -use rustc_data_structures::graph::{self, Direction, NodeIndex}; +use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING}; use rustc_data_structures::unify::{self, UnificationTable}; use middle::free_region::FreeRegionMap; use ty::{self, Ty, TyCtxt}; @@ -872,7 +872,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { let seeds: Vec<_> = givens.iter().cloned().collect(); for (fr, vid) in seeds { let seed_index = NodeIndex(vid.index as usize); - for succ_index in graph.depth_traverse(seed_index) { + for succ_index in graph.depth_traverse(seed_index, OUTGOING) { let succ_index = succ_index.0 as u32; if succ_index < self.num_vars() { let succ_vid = RegionVid { index: succ_index }; diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 99a87d1e760c..731471b0600f 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -292,11 +292,15 @@ impl Graph { } } - pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E> { + pub fn depth_traverse<'a>(&'a self, + start: NodeIndex, + direction: Direction) + -> DepthFirstTraversal<'a, N, E> { DepthFirstTraversal { graph: self, stack: vec![start], visited: BitVector::new(self.nodes.len()), + direction: direction, } } } @@ -371,6 +375,7 @@ pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> { graph: &'g Graph, stack: Vec, visited: BitVector, + direction: Direction, } impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { @@ -382,9 +387,10 @@ impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { continue; } - for (_, edge) in self.graph.outgoing_edges(idx) { - if !self.visited.contains(edge.target().node_id()) { - self.stack.push(edge.target()); + for (_, edge) in self.graph.adjacent_edges(idx, self.direction) { + let target = edge.source_or_target(self.direction); + if !self.visited.contains(target.node_id()) { + self.stack.push(target); } } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index b74e7e212262..e426e4d5b44a 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -195,7 +195,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; for &(_, source_def_id, source_dep_node) in sources { - let dependents = query.transitive_dependents(source_dep_node); + let dependents = query.transitive_successors(source_dep_node); for &(target_span, ref target_pass, _, ref target_dep_node) in targets { if !dependents.contains(&target_dep_node) { tcx.sess.span_err( diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 37d5f8937f17..5c68552b7185 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -14,10 +14,40 @@ use rustc::dep_graph::DepNode; use super::directory::DefPathIndex; +/// Data for use when recompiling the **current crate**. #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedDepGraph { pub nodes: Vec>, pub edges: Vec, + + /// These are hashes of two things: + /// - the HIR nodes in this crate + /// - the metadata nodes from dependent crates we use + /// + /// In each case, we store a hash summarizing the contents of + /// those items as they were at the time we did this compilation. + /// In the case of HIR nodes, this hash is derived by walking the + /// HIR itself. In the case of metadata nodes, the hash is loaded + /// from saved state. + /// + /// When we do the next compile, we will load these back up and + /// compare them against the hashes we see at that time, which + /// will tell us what has changed, either in this crate or in some + /// crate that we depend on. + pub hashes: Vec, +} + +/// Data for use when downstream crates get recompiled. +#[derive(Debug, RustcEncodable, RustcDecodable)] +pub struct SerializedMetadataHashes { + /// For each def-id defined in this crate that appears in the + /// metadata, we hash all the inputs that were used when producing + /// the metadata. We save this after compilation is done. Then, + /// when some downstream crate is being recompiled, it can compare + /// the hashes we saved against the hashes that it saw from + /// before; this will tell it which of the items in this crate + /// changed, which in turn implies what items in the downstream + /// crate need to be recompiled. pub hashes: Vec, } @@ -25,7 +55,9 @@ pub type SerializedEdge = (DepNode, DepNode); #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedHash { - pub index: DefPathIndex, + /// node being hashed; either a Hir or MetaData variant, in + /// practice + pub node: DepNode, /// the hash itself, computed by `calculate_item_hash` pub hash: u64, diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index f9e479745d10..35ef0917517c 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -10,7 +10,6 @@ //! Code to save/load the dep-graph from files. -use calculate_svh::SvhCalculate; use rbml::Error; use rbml::opaque::Decoder; use rustc::dep_graph::DepNode; @@ -131,20 +130,20 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - hashed_items: &[SerializedHash], + hashes: &[SerializedHash], retraced: &RetracedDefIdDirectory) -> DirtyNodes { let mut items_removed = false; let mut dirty_nodes = FnvHashSet(); - for hashed_item in hashed_items { - match retraced.def_id(hashed_item.index) { - Some(def_id) => { + for hash in hashes { + match hash.node.map_def(|&i| retraced.def_id(i)) { + Some(dep_node) => { // FIXME(#32753) -- should we use a distinct hash here - let current_hash = tcx.calculate_item_hash(def_id); + let current_hash = dep_node.hash(tcx).unwrap(); debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}", - def_id, current_hash, hashed_item.hash); - if current_hash != hashed_item.hash { - dirty_nodes.insert(DepNode::Hir(def_id)); + dep_node, current_hash, hash.hash); + if current_hash != hash.hash { + dirty_nodes.insert(dep_node); } } None => { diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index cbb3464f3ef4..40191cf758df 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use calculate_svh::SvhCalculate; use rbml::opaque::Encoder; use rustc::dep_graph::DepNode; use rustc::ty::TyCtxt; use rustc_serialize::{Encodable as RustcEncodable}; +use std::hash::{Hasher, SipHasher}; use std::io::{self, Cursor, Write}; use std::fs::{self, File}; +use std::path::PathBuf; use super::data::*; use super::directory::*; @@ -23,47 +24,57 @@ use super::util::*; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _ignore = tcx.dep_graph.in_ignore(); - if let Some(dep_graph) = dep_graph_path(tcx) { - // FIXME(#32754) lock file? - - // delete the old dep-graph, if any - if dep_graph.exists() { - match fs::remove_file(&dep_graph) { - Ok(()) => { } - Err(err) => { - tcx.sess.err( - &format!("unable to delete old dep-graph at `{}`: {}", - dep_graph.display(), err)); - return; - } - } - } + save_in(tcx, dep_graph_path(tcx), encode_dep_graph); + save_in(tcx, metadata_hash_path(tcx), encode_metadata_hashes); +} - // generate the data in a memory buffer - let mut wr = Cursor::new(Vec::new()); - match encode_dep_graph(tcx, &mut Encoder::new(&mut wr)) { +fn save_in<'a,'tcx,F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, opt_path_buf: Option, encode: F) + where F: FnOnce(TyCtxt<'a, 'tcx, 'tcx>, &mut Encoder) -> io::Result<()> +{ + let path_buf = match opt_path_buf { + Some(p) => p, + None => return + }; + + // FIXME(#32754) lock file? + + // delete the old dep-graph, if any + if path_buf.exists() { + match fs::remove_file(&path_buf) { Ok(()) => { } Err(err) => { tcx.sess.err( - &format!("could not encode dep-graph to `{}`: {}", - dep_graph.display(), err)); + &format!("unable to delete old dep-graph at `{}`: {}", + path_buf.display(), err)); return; } } + } - // write the data out - let data = wr.into_inner(); - match - File::create(&dep_graph) - .and_then(|mut file| file.write_all(&data)) - { - Ok(_) => { } - Err(err) => { - tcx.sess.err( - &format!("failed to write dep-graph to `{}`: {}", - dep_graph.display(), err)); - return; - } + // generate the data in a memory buffer + let mut wr = Cursor::new(Vec::new()); + match encode(tcx, &mut Encoder::new(&mut wr)) { + Ok(()) => { } + Err(err) => { + tcx.sess.err( + &format!("could not encode dep-graph to `{}`: {}", + path_buf.display(), err)); + return; + } + } + + // write the data out + let data = wr.into_inner(); + match + File::create(&path_buf) + .and_then(|mut file| file.write_all(&data)) + { + Ok(_) => { } + Err(err) => { + tcx.sess.err( + &format!("failed to write dep-graph to `{}`: {}", + path_buf.display(), err)); + return; } } } @@ -71,35 +82,20 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, encoder: &mut Encoder) -> io::Result<()> { - // Here we take advantage of how RBML allows us to skip around - // and encode the depgraph as a two-part structure: - // - // ``` - // [SerializedDepGraph] // tag 0 - // [DefIdDirectory] // tag 1 - // ``` - // - // Then later we can load the directory by skipping to find tag 1. - let query = tcx.dep_graph.query(); let mut builder = DefIdDirectoryBuilder::new(tcx); - // Create hashes for things we can persist. + // Create hashes for inputs. let hashes = query.nodes() .into_iter() - .filter_map(|dep_node| match dep_node { - DepNode::Hir(def_id) => { - assert!(def_id.is_local()); - builder.add(def_id) - .map(|index| { - // FIXME(#32753) -- should we use a distinct hash here - let hash = tcx.calculate_item_hash(def_id); - SerializedHash { index: index, hash: hash } - }) - } - _ => None + .filter_map(|dep_node| { + dep_node.hash(tcx) + .map(|hash| { + let node = builder.map(dep_node).unwrap(); + SerializedHash { node: node, hash: hash } + }) }) .collect(); @@ -133,3 +129,67 @@ pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } +pub fn encode_metadata_hashes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + encoder: &mut Encoder) + -> io::Result<()> +{ + let query = tcx.dep_graph.query(); + + let mut builder = DefIdDirectoryBuilder::new(tcx); + + let serialized_hashes = { + // Identify the `MetaData(X)` nodes where `X` is local. These are + // the metadata items we export. Downstream crates will want to + // see a hash that tells them whether we might have changed the + // metadata for a given item since they last compiled. + let meta_data_def_ids = + query.nodes() + .into_iter() + .filter_map(|dep_node| match dep_node { + DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id), + _ => None, + }); + + // To create the hash for each item `X`, we don't hash the raw + // bytes of the metadata (though in principle we could). Instead, + // we walk the predecessors of `MetaData(X)` from the + // dep-graph. This corresponds to all the inputs that were read to + // construct the metadata. To create the hash for the metadata, we + // hash (the hash of) all of those inputs. + let hashes = + meta_data_def_ids + .map(|def_id| { + let mut state = SipHasher::new(); + for node in query.transitive_predecessors(DepNode::MetaData(def_id)) { + if let Some(hash) = node.hash(tcx) { + state.write_u64(hash.to_le()); + } + } + (def_id, state.finish()) + }); + + // Now create the `SerializedHash` data structures that others + // will load later. + let hashes = + hashes + .map(|(def_id, hash)| { + let index = builder.add(def_id).unwrap(); + SerializedHash { + node: DepNode::MetaData(index), + hash: hash + } + }); + + // Collect these up into a vector. + SerializedMetadataHashes { + hashes: hashes.collect() + } + }; + + // Encode everything. + let directory = builder.into_directory(); + try!(directory.encode(encoder)); + try!(serialized_hashes.encode(encoder)); + + Ok(()) +} diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs index 754292ba3830..8a3455831237 100644 --- a/src/librustc_incremental/persist/util.rs +++ b/src/librustc_incremental/persist/util.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use calculate_svh::SvhCalculate; +use rustc::dep_graph::DepNode; +use rustc::hir::def_id::DefId; use rustc::middle::cstore::LOCAL_CRATE; use rustc::ty::TyCtxt; @@ -16,6 +19,14 @@ use std::io; use std::path::{PathBuf, Path}; pub fn dep_graph_path(tcx: TyCtxt) -> Option { + path(tcx, "local") +} + +pub fn metadata_hash_path(tcx: TyCtxt) -> Option { + path(tcx, "metadata") +} + +fn path(tcx: TyCtxt, suffix: &str) -> Option { // For now, just save/load dep-graph from // directory/dep_graph.rbml tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| { @@ -31,9 +42,10 @@ pub fn dep_graph_path(tcx: TyCtxt) -> Option { let crate_name = tcx.crate_name(LOCAL_CRATE); let crate_disambiguator = tcx.crate_disambiguator(LOCAL_CRATE); - let file_name = format!("dep-graph-{}-{}.bin", + let file_name = format!("{}-{}.{}.bin", crate_name, - crate_disambiguator); + crate_disambiguator, + suffix); Some(incr_dir.join(file_name)) }) } @@ -58,3 +70,22 @@ fn create_dir_racy(path: &Path) -> io::Result<()> { Err(e) => Err(e), } } + +pub trait DepNodeHash { + /// Hash this dep-node, if it is of the kind that we know how to + /// hash. + fn hash<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option; +} + +impl DepNodeHash for DepNode { + fn hash<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { + match *self { + DepNode::Hir(def_id) => { + // FIXME(#32753) -- should we use a distinct hash here + assert!(def_id.is_local()); + Some(tcx.calculate_item_hash(def_id)) + } + _ => None + } + } +} diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 65c3aa12ba6c..481154ba29f8 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -47,6 +47,7 @@ use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::util::common::time; use rustc::mir::mir_map::MirMap; +use rustc_data_structures::graph::OUTGOING; use session::config::{self, NoDebugInfo, FullDebugInfo}; use session::Session; use _match; @@ -1368,7 +1369,7 @@ fn build_cfg<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // return slot alloca. This can cause errors related to clean-up due to // the clobbering of the existing value in the return slot. fn has_nested_returns(tcx: TyCtxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool { - for index in cfg.graph.depth_traverse(cfg.entry) { + for index in cfg.graph.depth_traverse(cfg.entry, OUTGOING) { let n = cfg.graph.node_data(index); match tcx.map.find(n.id()) { Some(hir_map::NodeExpr(ex)) => { From c7840cfe140a1f523a4fa399344da431022e3cb6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 6 Apr 2016 17:54:40 -0400 Subject: [PATCH 09/21] make the filename computation take a cratenum --- src/librustc_incremental/persist/save.rs | 3 ++- src/librustc_incremental/persist/util.rs | 15 ++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 40191cf758df..868f2ee4244a 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -10,6 +10,7 @@ use rbml::opaque::Encoder; use rustc::dep_graph::DepNode; +use rustc::middle::cstore::LOCAL_CRATE; use rustc::ty::TyCtxt; use rustc_serialize::{Encodable as RustcEncodable}; use std::hash::{Hasher, SipHasher}; @@ -25,7 +26,7 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _ignore = tcx.dep_graph.in_ignore(); save_in(tcx, dep_graph_path(tcx), encode_dep_graph); - save_in(tcx, metadata_hash_path(tcx), encode_metadata_hashes); + save_in(tcx, metadata_hash_path(tcx, LOCAL_CRATE), encode_metadata_hashes); } fn save_in<'a,'tcx,F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, opt_path_buf: Option, encode: F) diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs index 8a3455831237..7acfdb5fffe9 100644 --- a/src/librustc_incremental/persist/util.rs +++ b/src/librustc_incremental/persist/util.rs @@ -16,17 +16,18 @@ use rustc::ty::TyCtxt; use std::fs; use std::io; -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; +use syntax::ast; pub fn dep_graph_path(tcx: TyCtxt) -> Option { - path(tcx, "local") + path(tcx, LOCAL_CRATE, "local") } -pub fn metadata_hash_path(tcx: TyCtxt) -> Option { - path(tcx, "metadata") +pub fn metadata_hash_path(tcx: TyCtxt, cnum: ast::CrateNum) -> Option { + path(tcx, cnum, "metadata") } -fn path(tcx: TyCtxt, suffix: &str) -> Option { +fn path(tcx: TyCtxt, cnum: ast::CrateNum, suffix: &str) -> Option { // For now, just save/load dep-graph from // directory/dep_graph.rbml tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| { @@ -40,8 +41,8 @@ fn path(tcx: TyCtxt, suffix: &str) -> Option { } } - let crate_name = tcx.crate_name(LOCAL_CRATE); - let crate_disambiguator = tcx.crate_disambiguator(LOCAL_CRATE); + let crate_name = tcx.crate_name(cnum); + let crate_disambiguator = tcx.crate_disambiguator(cnum); let file_name = format!("{}-{}.{}.bin", crate_name, crate_disambiguator, From 8f3a8c24cd667da6c1e8ba751ba9896c7f9ad293 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 22 Apr 2016 15:18:02 -0400 Subject: [PATCH 10/21] always encode variant fields we need them to be able to retrace. --- src/librustc_metadata/decoder.rs | 5 ++++- src/librustc_metadata/encoder.rs | 9 +++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e233dda7e91e..d7499342bf5e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -71,7 +71,10 @@ impl crate_metadata { fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc { match self.get_item(item_id) { - None => bug!("lookup_item: id not found: {:?}", item_id), + None => bug!("lookup_item: id not found: {:?} in crate {:?} with number {}", + item_id, + self.name, + self.cnum), Some(d) => d } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 8a16a4b4a634..1b313aac7cac 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -267,12 +267,8 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let vid = variant.did; let variant_node_id = ecx.local_id(vid); - if let ty::VariantKind::Struct = variant.kind() { - // tuple-like enum variant fields aren't really items so - // don't try to encode them. - for field in &variant.fields { - encode_field(ecx, rbml_w, field, index); - } + for field in &variant.fields { + encode_field(ecx, rbml_w, field, index); } let _task = index.record(vid, rbml_w); @@ -306,6 +302,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id); rbml_w.end_tag(); + disr_val = disr_val.wrap_incr(); } } From 08837d2975d5c642a4e625501ef452f43e217dc6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 4 May 2016 20:44:22 -0400 Subject: [PATCH 11/21] pass revision and incr_comp directory to auxbuild This is needed for incremental compilation harness to support cross-crate testing. Also support cfg for typechecking prettyprint --- src/tools/compiletest/src/header.rs | 16 +++++++++++++ src/tools/compiletest/src/runtest.rs | 34 ++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index b5cebe2e3ea2..7593033ffe39 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -162,6 +162,11 @@ pub struct TestProps { pub forbid_output: Vec, // Revisions to test for incremental compilation. pub revisions: Vec, + // Directory (if any) to use for incremental compilation. This is + // not set by end-users; rather it is set by the incremental + // testing harness and used when generating compilation + // arguments. (In particular, it propagates to the aux-builds.) + pub incremental_dir: Option, } impl TestProps { @@ -197,9 +202,20 @@ impl TestProps { pretty_mode: format!("normal"), pretty_compare_only: pretty_compare_only, forbid_output: forbid_output, + incremental_dir: None, } } + pub fn from_aux_file(&self, testfile: &Path, cfg: Option<&str>) -> Self { + let mut props = TestProps::new(); + + // copy over select properties to the aux build: + props.incremental_dir = self.incremental_dir.clone(); + props.load_from(testfile, cfg); + + props + } + pub fn from_file(testfile: &Path) -> Self { let mut props = TestProps::new(); props.load_from(testfile, None); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a213c6d2d54a..f89ff6b38492 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -63,10 +63,6 @@ pub fn run(config: Config, testpaths: &TestPaths) { for revision in &base_props.revisions { let mut revision_props = base_props.clone(); revision_props.load_from(&testpaths.file, Some(&revision)); - revision_props.compile_flags.extend(vec![ - format!("--cfg"), - format!("{}", revision), - ]); let rev_cx = TestCx { config: &config, props: &revision_props, @@ -383,6 +379,12 @@ actual:\n\ self.config.build_base.to_str().unwrap().to_owned(), "-L".to_owned(), aux_dir.to_str().unwrap().to_owned()); + if let Some(revision) = self.revision { + args.extend(vec![ + format!("--cfg"), + format!("{}", revision), + ]); + } args.extend(self.split_maybe_args(&self.config.target_rustcflags)); args.extend(self.props.compile_flags.iter().cloned()); // FIXME (#9639): This needs to handle non-utf8 paths @@ -1102,7 +1104,7 @@ actual:\n\ if self.props.build_aux_docs { for rel_ab in &self.props.aux_builds { let aux_testpaths = self.compute_aux_test_paths(rel_ab); - let aux_props = TestProps::from_file(&aux_testpaths.file); + let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision); let aux_cx = TestCx { config: self.config, props: &aux_props, @@ -1186,7 +1188,7 @@ actual:\n\ for rel_ab in &self.props.aux_builds { let aux_testpaths = self.compute_aux_test_paths(rel_ab); - let aux_props = TestProps::from_file(&aux_testpaths.file); + let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision); let mut crate_type = if aux_props.no_prefer_dynamic { Vec::new() } else { @@ -1291,6 +1293,21 @@ actual:\n\ self.config.build_base.to_str().unwrap().to_owned(), format!("--target={}", target)); + if let Some(revision) = self.revision { + args.extend(vec![ + format!("--cfg"), + format!("{}", revision), + ]); + } + + if let Some(ref incremental_dir) = self.props.incremental_dir { + args.extend(vec![ + format!("-Z"), + format!("incremental={}", incremental_dir.display()), + ]); + } + + match self.config.mode { CompileFail | ParseFail | @@ -1980,10 +1997,7 @@ actual:\n\ // Add an extra flag pointing at the incremental directory. let mut revision_props = self.props.clone(); - revision_props.compile_flags.extend(vec![ - format!("-Z"), - format!("incremental={}", incremental_dir.display()), - ]); + revision_props.incremental_dir = Some(incremental_dir); let revision_cx = TestCx { config: self.config, From 0082fc0ad4d9f8c1cbac7326be2db01f866bfef1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 6 May 2016 05:01:09 -0400 Subject: [PATCH 12/21] change svh to store a u64 We used to store a u64 converted to a String for some reason. Now we don't. --- src/librustc/hir/svh.rs | 66 ++++++++--------------- src/librustc/ty/util.rs | 2 +- src/librustc_incremental/calculate_svh.rs | 13 +++-- src/librustc_metadata/decoder.rs | 6 +-- src/librustc_metadata/encoder.rs | 4 +- src/librustc_metadata/loader.rs | 2 +- 6 files changed, 38 insertions(+), 55 deletions(-) diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs index 1536f884b098..f0294ad633ad 100644 --- a/src/librustc/hir/svh.rs +++ b/src/librustc/hir/svh.rs @@ -10,60 +10,34 @@ //! Calculation and management of a Strict Version Hash for crates //! -//! # Today's ABI problem -//! -//! In today's implementation of rustc, it is incredibly difficult to achieve -//! forward binary compatibility without resorting to C-like interfaces. Within -//! rust code itself, abi details such as symbol names suffer from a variety of -//! unrelated factors to code changing such as the "def id drift" problem. This -//! ends up yielding confusing error messages about metadata mismatches and -//! such. -//! -//! The core of this problem is when an upstream dependency changes and -//! downstream dependents are not recompiled. This causes compile errors because -//! the upstream crate's metadata has changed but the downstream crates are -//! still referencing the older crate's metadata. -//! -//! This problem exists for many reasons, the primary of which is that rust does -//! not currently support forwards ABI compatibility (in place upgrades of a -//! crate). -//! -//! # SVH and how it alleviates the problem -//! -//! With all of this knowledge on hand, this module contains the implementation -//! of a notion of a "Strict Version Hash" for a crate. This is essentially a -//! hash of all contents of a crate which can somehow be exposed to downstream -//! crates. -//! -//! This hash is currently calculated by just hashing the AST, but this is -//! obviously wrong (doc changes should not result in an incompatible ABI). -//! Implementation-wise, this is required at this moment in time. -//! -//! By encoding this strict version hash into all crate's metadata, stale crates -//! can be detected immediately and error'd about by rustc itself. -//! -//! # Relevant links -//! -//! Original issue: https://github.com/rust-lang/rust/issues/10207 +//! The SVH is used for incremental compilation to track when HIR +//! nodes have changed between compilations, and also to detect +//! mismatches where we have two versions of the same crate that were +//! compiled from distinct sources. use std::fmt; +use std::hash::{Hash, Hasher}; -#[derive(Clone, Eq, Hash, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Svh { - hash: String, + hash: u64, } impl Svh { /// Create a new `Svh` given the hash. If you actually want to /// compute the SVH from some HIR, you want the `calculate_svh` - /// function found in `librustc_trans`. - pub fn new(hash: String) -> Svh { - assert!(hash.len() == 16); + /// function found in `librustc_incremental`. + pub fn new(hash: u64) -> Svh { Svh { hash: hash } } - pub fn from_hash(hash: u64) -> Svh { - return Svh::new((0..64).step_by(4).map(|i| hex(hash >> i)).collect()); + pub fn as_u64(&self) -> u64 { + self.hash + } + + pub fn to_string(&self) -> String { + let hash = self.hash; + return (0..64).step_by(4).map(|i| hex(hash >> i)).collect(); fn hex(b: u64) -> char { let b = (b & 0xf) as u8; @@ -74,14 +48,16 @@ impl Svh { b as char } } +} - pub fn as_str<'a>(&'a self) -> &'a str { - &self.hash +impl Hash for Svh { + fn hash(&self, state: &mut H) where H: Hasher { + self.hash.to_le().hash(state); } } impl fmt::Display for Svh { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad(self.as_str()) + f.pad(&self.to_string()) } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 08909861d3f6..4f6188ea3c51 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -368,7 +368,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } else { tcx.sess.cstore.crate_hash(did.krate) }; - h.as_str().hash(state); + h.hash(state); did.index.hash(state); }; let mt = |state: &mut SipHasher, mt: TypeAndMut| { diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index f134f3c3f104..24ecce114874 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -72,12 +72,14 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { attr.node.value.hash(&mut state); } - Svh::from_hash(state.finish()) + Svh::new(state.finish()) } fn calculate_item_hash(self, def_id: DefId) -> u64 { assert!(def_id.is_local()); + debug!("calculate_item_hash(def_id={:?})", def_id); + let mut state = SipHasher::new(); { @@ -89,11 +91,16 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { intravisit::walk_crate(&mut visit, krate); } else { let node_id = self.map.as_local_node_id(def_id).unwrap(); - visit.visit_item(self.map.expect_item(node_id)); + let item = self.map.expect_item(node_id); + visit.visit_item(item); } } - state.finish() + let hash = state.finish(); + + debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, hash); + + hash } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d7499342bf5e..5e4c9f39e35f 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1251,7 +1251,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec { reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| { let name = docstr(depdoc, tag_crate_dep_crate_name); - let hash = Svh::new(docstr(depdoc, tag_crate_dep_hash)); + let hash = Svh::new(reader::doc_as_u64(reader::get_doc(depdoc, tag_crate_dep_hash))); let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked); let explicitly_linked = reader::doc_as_u8(doc) != 0; CrateDep { @@ -1275,14 +1275,14 @@ fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> { pub fn maybe_get_crate_hash(data: &[u8]) -> Option { let cratedoc = rbml::Doc::new(data); reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| { - Svh::new(doc.as_str_slice().to_string()) + Svh::new(reader::doc_as_u64(doc)) }) } pub fn get_crate_hash(data: &[u8]) -> Svh { let cratedoc = rbml::Doc::new(data); let hashdoc = reader::get_doc(cratedoc, tag_crate_hash); - Svh::new(hashdoc.as_str_slice().to_string()) + Svh::new(reader::doc_as_u64(hashdoc)) } pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 1b313aac7cac..928601095b07 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1793,14 +1793,14 @@ fn encode_crate_dep(rbml_w: &mut Encoder, rbml_w.start_tag(tag_crate_dep); rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name()); let hash = decoder::get_crate_hash(dep.data()); - rbml_w.wr_tagged_str(tag_crate_dep_hash, hash.as_str()); + rbml_w.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64()); rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked, dep.explicitly_linked.get() as u8); rbml_w.end_tag(); } fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) { - rbml_w.wr_tagged_str(tag_crate_hash, hash.as_str()); + rbml_w.wr_tagged_u64(tag_crate_hash, hash.as_u64()); } fn encode_rustc_version(rbml_w: &mut Encoder) { diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 4ecb7a28ef76..a5b1c3d301b1 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -620,7 +620,7 @@ impl<'a> Context<'a> { info!("Rejecting via hash: expected {} got {}", *myhash, hash); self.rejected_via_hash.push(CrateMismatch { path: libpath.to_path_buf(), - got: myhash.as_str().to_string() + got: myhash.to_string() }); return None; } From 303fdc17f6bb842668e0fdd1e1a2c16841ae7373 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 6 May 2016 05:02:05 -0400 Subject: [PATCH 13/21] cleanup dep-graph debugging code Create some re-usable filtering subroutines. --- src/librustc/dep_graph/debug.rs | 69 ++++++++++++++++++++ src/librustc/dep_graph/mod.rs | 1 + src/librustc_incremental/assert_dep_graph.rs | 28 +++----- 3 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 src/librustc/dep_graph/debug.rs diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs new file mode 100644 index 000000000000..15b0380374c6 --- /dev/null +++ b/src/librustc/dep_graph/debug.rs @@ -0,0 +1,69 @@ +// Copyright 2012-2015 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. + +//! Code for debugging the dep-graph. + +use super::dep_node::DepNode; +use std::error::Error; +use std::fmt::Debug; + +/// A dep-node filter goes from a user-defined string to a query over +/// nodes. Right now the format is like this: +/// +/// x & y & z +/// +/// where the format-string of the dep-node must contain `x`, `y`, and +/// `z`. +#[derive(Debug)] +pub struct DepNodeFilter { + text: String +} + +impl DepNodeFilter { + pub fn new(text: &str) -> Self { + DepNodeFilter { + text: text.trim().to_string() + } + } + + /// True if all nodes always pass the filter. + pub fn accepts_all(&self) -> bool { + self.text.is_empty() + } + + /// Tests whether `node` meets the filter, returning true if so. + pub fn test(&self, node: &DepNode) -> bool { + let debug_str = format!("{:?}", node); + self.text.split("&") + .map(|s| s.trim()) + .all(|f| debug_str.contains(f)) + } +} + +/// A filter like `F -> G` where `F` and `G` are valid dep-node +/// filters. This can be used to test the source/target independently. +pub struct EdgeFilter { + pub source: DepNodeFilter, + pub target: DepNodeFilter, +} + +impl EdgeFilter { + pub fn new(test: &str) -> Result> { + let parts: Vec<_> = test.split("->").collect(); + if parts.len() != 2 { + Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into()) + } else { + Ok(EdgeFilter { + source: DepNodeFilter::new(parts[0]), + target: DepNodeFilter::new(parts[1]), + }) + } + } +} diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 9c1bc3324dbb..e65f6bbcf7aa 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +pub mod debug; mod dep_node; mod dep_tracking_map; mod edges; diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index e426e4d5b44a..9dc50a630640 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -44,6 +44,7 @@ use graphviz as dot; use rustc::dep_graph::{DepGraphQuery, DepNode}; +use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; use rustc::hir::def_id::DefId; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet}; @@ -220,12 +221,11 @@ fn dump_graph(tcx: TyCtxt) { let nodes = match env::var("RUST_DEP_GRAPH_FILTER") { Ok(string) => { // Expect one of: "-> target", "source -> target", or "source ->". - let parts: Vec<_> = string.split("->").collect(); - if parts.len() > 2 { - bug!("Invalid RUST_DEP_GRAPH_FILTER: expected '[source] -> [target]'"); - } - let sources = node_set(&query, &parts[0]); - let targets = node_set(&query, &parts[1]); + let edge_filter = EdgeFilter::new(&string).unwrap_or_else(|e| { + bug!("invalid filter: {}", e) + }); + let sources = node_set(&query, &edge_filter.source); + let targets = node_set(&query, &edge_filter.target); filter_nodes(&query, &sources, &targets) } Err(_) => { @@ -295,26 +295,16 @@ impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph { // Given an optional filter like `"x,y,z"`, returns either `None` (no // filter) or the set of nodes whose labels contain all of those // substrings. -fn node_set(query: &DepGraphQuery, filter: &str) +fn node_set(query: &DepGraphQuery, filter: &DepNodeFilter) -> Option>> { debug!("node_set(filter={:?})", filter); - if filter.trim().is_empty() { + if filter.accepts_all() { return None; } - let filters: Vec<&str> = filter.split("&").map(|s| s.trim()).collect(); - - debug!("node_set: filters={:?}", filters); - - Some(query.nodes() - .into_iter() - .filter(|n| { - let s = format!("{:?}", n); - filters.iter().all(|f| s.contains(f)) - }) - .collect()) + Some(query.nodes().into_iter().filter(|n| filter.test(n)).collect()) } fn filter_nodes(query: &DepGraphQuery, From b01919a1443615f2ee78f91515e8f01dc2591177 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 6 May 2016 14:52:57 -0400 Subject: [PATCH 14/21] allow retracing paths across crates For external crates, we must build up a map that goes from the DefKey to the DefIndex. We do this by iterating over each index that is found in the metadata and loading the associated DefKey. --- src/librustc/hir/map/definitions.rs | 37 +++----------- src/librustc/hir/map/mod.rs | 7 ++- src/librustc/middle/cstore.rs | 17 +++++-- src/librustc/ty/context.rs | 48 ++++++++++++++++++- src/librustc_incremental/persist/directory.rs | 2 +- src/librustc_metadata/creader.rs | 1 + src/librustc_metadata/csearch.rs | 9 ++++ src/librustc_metadata/cstore.rs | 10 +++- src/librustc_metadata/decoder.rs | 36 +++++++++++++- 9 files changed, 123 insertions(+), 44 deletions(-) diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 358301ab4042..457511cdbc3b 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -82,8 +82,10 @@ impl DefPath { let mut data = vec![]; let mut index = Some(start_index); loop { + debug!("DefPath::make: krate={:?} index={:?}", krate, index); let p = index.unwrap(); let key = get_key(p); + debug!("DefPath::make: key={:?}", key); match key.disambiguated_data.data { DefPathData::CrateRoot => { assert!(key.parent.is_none()); @@ -178,6 +180,10 @@ impl Definitions { self.data[index.as_usize()].key.clone() } + pub fn def_index_for_def_key(&self, key: DefKey) -> Option { + self.key_map.get(&key).cloned() + } + /// Returns the path from the crate root to `index`. The root /// nodes are not included in the path (i.e., this will be an /// empty vector for the crate root). For an inlined item, this @@ -208,37 +214,6 @@ impl Definitions { } } - pub fn retrace_path(&self, path: &DefPath) -> Option { - debug!("retrace_path(path={:?})", path); - - // we assume that we only want to retrace paths relative to - // the crate root - assert!(path.is_local()); - - let root_key = DefKey { - parent: None, - disambiguated_data: DisambiguatedDefPathData { - data: DefPathData::CrateRoot, - disambiguator: 0, - }, - }; - let root_id = self.key_map[&root_key]; - - debug!("retrace_path: root_id={:?}", root_id); - - let mut id = root_id; - for data in &path.data { - let key = DefKey { parent: Some(id), disambiguated_data: data.clone() }; - debug!("key = {:?}", key); - id = match self.key_map.get(&key) { - Some(&id) => id, - None => return None - }; - } - - Some(id) - } - pub fn create_def_with_parent(&mut self, parent: Option, node_id: ast::NodeId, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index e3976482dca8..2f310806a742 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -19,7 +19,7 @@ use dep_graph::{DepGraph, DepNode}; use middle::cstore::InlinedItem; use middle::cstore::InlinedItem as II; -use hir::def_id::{CRATE_DEF_INDEX, DefId}; +use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, }; @@ -285,9 +285,8 @@ impl<'ast> Map<'ast> { self.definitions.borrow().def_path(def_id.index) } - pub fn retrace_path(&self, path: &DefPath) -> Option { - self.definitions.borrow().retrace_path(path) - .map(DefId::local) + pub fn def_index_for_def_key(&self, def_key: DefKey) -> Option { + self.definitions.borrow().def_index_for_def_key(def_key) } pub fn local_def_id(&self, node: NodeId) -> DefId { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 17c6442c019b..e5a8c1d1b4e6 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -22,12 +22,13 @@ // are *mostly* used as a part of that interface, but these should // probably get a better home if someone can find one. -use hir::svh::Svh; -use hir::map as hir_map; use hir::def::{self, Def}; +use hir::def_id::{DefId, DefIndex}; +use hir::map as hir_map; +use hir::map::definitions::DefKey; +use hir::svh::Svh; use middle::lang_items; use ty::{self, Ty, TyCtxt, VariantKind}; -use hir::def_id::{DefId, DefIndex}; use mir::repr::Mir; use mir::mir_map::MirMap; use session::Session; @@ -234,6 +235,10 @@ pub trait CrateStore<'tcx> { fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec; // resolve + fn def_index_for_def_key(&self, + cnum: ast::CrateNum, + def: DefKey) + -> Option; fn def_key(&self, def: DefId) -> hir_map::DefKey; fn relative_def_path(&self, def: DefId) -> hir_map::DefPath; fn variant_kind(&self, def_id: DefId) -> Option; @@ -361,6 +366,12 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> Vec>> { bug!("provided_trait_methods") } fn trait_item_def_ids(&self, def: DefId) -> Vec { bug!("trait_item_def_ids") } + fn def_index_for_def_key(&self, + cnum: ast::CrateNum, + def: DefKey) + -> Option { + None + } // impl info fn impl_items(&self, impl_def_id: DefId) -> Vec diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 39fe744c67d0..ea169b1d3b65 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -11,13 +11,14 @@ //! type context book-keeping use dep_graph::{DepGraph, DepTrackingMap}; -use hir::map as ast_map; use session::Session; use lint; use middle; use middle::cstore::LOCAL_CRATE; use hir::def::DefMap; -use hir::def_id::DefId; +use hir::def_id::{DefId, DefIndex}; +use hir::map as ast_map; +use hir::map::{DefKey, DefPath, DefPathData, DisambiguatedDefPathData}; use middle::free_region::FreeRegionMap; use middle::region::RegionMaps; use middle::resolve_lifetime; @@ -511,6 +512,49 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + /// Given a def-key `key` and a crate `krate`, finds the def-index + /// that `krate` assigned to `key`. This `DefIndex` will always be + /// relative to `krate`. + /// + /// Returns `None` if there is no `DefIndex` with that key. + pub fn def_index_for_def_key(self, krate: ast::CrateNum, key: DefKey) + -> Option { + if krate == LOCAL_CRATE { + self.map.def_index_for_def_key(key) + } else { + self.sess.cstore.def_index_for_def_key(krate, key) + } + } + + pub fn retrace_path(self, path: &DefPath) -> Option { + debug!("retrace_path(path={:?})", path); + + let root_key = DefKey { + parent: None, + disambiguated_data: DisambiguatedDefPathData { + data: DefPathData::CrateRoot, + disambiguator: 0, + }, + }; + + let root_index = self.def_index_for_def_key(path.krate, root_key) + .expect("no root key?"); + + debug!("retrace_path: root_index={:?}", root_index); + + let mut index = root_index; + for data in &path.data { + let key = DefKey { parent: Some(index), disambiguated_data: data.clone() }; + debug!("retrace_path: key={:?}", key); + match self.def_index_for_def_key(path.krate, key) { + Some(i) => index = i, + None => return None, + } + } + + Some(DefId { krate: path.krate, index: index }) + } + pub fn type_parameter_def(self, node_id: NodeId) -> ty::TypeParameterDef<'tcx> diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs index e256b7cf7d0e..077531587536 100644 --- a/src/librustc_incremental/persist/directory.rs +++ b/src/librustc_incremental/persist/directory.rs @@ -41,7 +41,7 @@ impl DefIdDirectory { pub fn retrace(&self, tcx: TyCtxt) -> RetracedDefIdDirectory { let ids = self.paths.iter() - .map(|path| tcx.map.retrace_path(path)) + .map(|path| tcx.retrace_path(path)) .collect(); RetracedDefIdDirectory { ids: ids } } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 63c6af704bbf..0eacc0907bc2 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -319,6 +319,7 @@ impl<'a> CrateReader<'a> { extern_crate: Cell::new(None), index: decoder::load_index(metadata.as_slice()), xref_index: decoder::load_xrefs(metadata.as_slice()), + key_map: decoder::load_key_map(metadata.as_slice()), data: metadata, cnum_map: RefCell::new(cnum_map), cnum: cnum, diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 54e078a16f0a..b87b5492f044 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -22,6 +22,7 @@ use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; +use rustc::hir::map::DefKey; use rustc::mir::repr::Mir; use rustc::mir::mir_map::MirMap; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; @@ -408,6 +409,14 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_reachable_ids(&cdata) } + fn def_index_for_def_key(&self, + cnum: ast::CrateNum, + def: DefKey) + -> Option { + let cdata = self.get_crate_data(cnum); + cdata.key_map.get(&def).cloned() + } + /// Returns the `DefKey` for a given `DefId`. This indicates the /// parent `DefId` as well as some idea of what kind of data the /// `DefId` refers to. diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index d3c4c5b02920..2e1bdf21c9a5 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -21,7 +21,8 @@ use index; use loader; use rustc::dep_graph::DepGraph; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefIndex, DefId}; +use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; use rustc::middle::cstore::{ExternCrate}; use rustc::session::config::PanicStrategy; @@ -79,6 +80,13 @@ pub struct crate_metadata { pub index: index::Index, pub xref_index: index::DenseIndex, + /// For each public item in this crate, we encode a key. When the + /// crate is loaded, we read all the keys and put them in this + /// hashmap, which gives the reverse mapping. This allows us to + /// quickly retrace a `DefPath`, which is needed for incremental + /// compilation support. + pub key_map: FnvHashMap, + /// Flag if this crate is required by an rlib version of this crate, or in /// other words whether it was explicitly linked to. An example of a crate /// where this is false is when an allocator crate is injected into the diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5e4c9f39e35f..b6f35074b7dc 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -25,6 +25,7 @@ use tydecode::TyDecoder; use rustc::hir::svh::Svh; use rustc::hir::map as hir_map; +use rustc::hir::map::DefKey; use rustc::util::nodemap::FnvHashMap; use rustc::hir; use rustc::session::config::PanicStrategy; @@ -95,6 +96,29 @@ pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { index::DenseIndex::from_buf(index.data, index.start, index.end) } +// Go through each item in the metadata and create a map from that +// item's def-key to the item's DefIndex. +pub fn load_key_map(data: &[u8]) -> FnvHashMap { + let root_doc = rbml::Doc::new(data); + let items_doc = reader::get_doc(root_doc, tag_items); + let items_data_doc = reader::get_doc(items_doc, tag_items_data); + reader::docs(items_data_doc) + .filter(|&(tag, _)| tag == tag_items_data_item) + .map(|(_, item_doc)| { + // load def-key from item + let key = item_def_key(item_doc); + + // load def-index from item; we only encode the full def-id, + // so just pull out the index + let def_id_doc = reader::get_doc(item_doc, tag_def_id); + let def_id = untranslated_def_id(def_id_doc); + assert!(def_id.is_local()); // local to the crate we are decoding, that is + + (key, def_id.index) + }) + .collect() +} + #[derive(Clone, Copy, Debug, PartialEq)] enum Family { ImmStatic, // c @@ -193,10 +217,14 @@ fn item_symbol(item: rbml::Doc) -> String { reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string() } -fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId { +fn untranslated_def_id(d: rbml::Doc) -> DefId { let id = reader::doc_as_u64(d); let index = DefIndex::new((id & 0xFFFF_FFFF) as usize); - let def_id = DefId { krate: (id >> 32) as u32, index: index }; + DefId { krate: (id >> 32) as u32, index: index } +} + +fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId { + let def_id = untranslated_def_id(d); translate_def_id(cdata, def_id) } @@ -1750,6 +1778,10 @@ pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 't pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { debug!("def_key: id={:?}", id); let item_doc = cdata.lookup_item(id); + item_def_key(item_doc) +} + +fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { match reader::maybe_get_doc(item_doc, tag_def_key) { Some(def_key_doc) => { let mut decoder = reader::Decoder::new(def_key_doc); From 3a2edd7e613638a61bf70499e4c225c2fec36a5d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 6 May 2016 15:09:31 -0400 Subject: [PATCH 15/21] load/save hashes of metadata This commit reorganizes how the persist code treats hashing. The idea is that each crate saves a file containing hashes representing the metadata for each item X. When we see a read from `MetaData(X)`, we can load this hash up (if we don't find a file for that crate, we just use the SVH for the entire crate). To compute the hash for `MetaData(Y)`, where Y is some local item, we examine all the predecessors of the `MetaData(Y)` node and hash their hashes together. --- src/librustc_incremental/persist/data.rs | 43 ++++- src/librustc_incremental/persist/directory.rs | 19 +-- src/librustc_incremental/persist/hash.rs | 158 ++++++++++++++++++ src/librustc_incremental/persist/load.rs | 5 +- src/librustc_incremental/persist/mod.rs | 1 + src/librustc_incremental/persist/save.rs | 94 +++++------ src/librustc_incremental/persist/util.rs | 21 --- 7 files changed, 249 insertions(+), 92 deletions(-) create mode 100644 src/librustc_incremental/persist/hash.rs diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 5c68552b7185..f57ab19a5256 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -11,6 +11,7 @@ //! The data that we will serialize and deserialize. use rustc::dep_graph::DepNode; +use rustc::hir::def_id::DefIndex; use super::directory::DefPathIndex; @@ -34,30 +35,56 @@ pub struct SerializedDepGraph { /// compare them against the hashes we see at that time, which /// will tell us what has changed, either in this crate or in some /// crate that we depend on. + /// + /// Because they will be reloaded, we don't store the DefId (which + /// will be different when we next compile) related to each node, + /// but rather the `DefPathIndex`. This can then be retraced + /// to find the current def-id. pub hashes: Vec, } +pub type SerializedEdge = (DepNode, DepNode); + +#[derive(Debug, RustcEncodable, RustcDecodable)] +pub struct SerializedHash { + /// node being hashed; either a Hir or MetaData variant, in + /// practice + pub node: DepNode, + + /// the hash itself, computed by `calculate_item_hash` + pub hash: u64, +} + /// Data for use when downstream crates get recompiled. #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedMetadataHashes { /// For each def-id defined in this crate that appears in the /// metadata, we hash all the inputs that were used when producing - /// the metadata. We save this after compilation is done. Then, + /// the metadata. We save this after compilation is done. Then, /// when some downstream crate is being recompiled, it can compare /// the hashes we saved against the hashes that it saw from /// before; this will tell it which of the items in this crate /// changed, which in turn implies what items in the downstream /// crate need to be recompiled. - pub hashes: Vec, + /// + /// Note that we store the def-ids here. This is because we don't + /// reload this file when we recompile this crate, we will just + /// regenerate it completely with the current hashes and new def-ids. + /// + /// Then downstream creates will load up their + /// `SerializedDepGraph`, which may contain `MetaData(X)` nodes + /// where `X` refers to some item in this crate. That `X` will be + /// a `DefPathIndex` that gets retracted to the current `DefId` + /// (matching the one found in this structure). + pub hashes: Vec, } -pub type SerializedEdge = (DepNode, DepNode); - +/// The hash for some metadata that (when saving) will be exported +/// from this crate, or which (when importing) was exported by an +/// upstream crate. #[derive(Debug, RustcEncodable, RustcDecodable)] -pub struct SerializedHash { - /// node being hashed; either a Hir or MetaData variant, in - /// practice - pub node: DepNode, +pub struct SerializedMetadataHash { + pub def_index: DefIndex, /// the hash itself, computed by `calculate_item_hash` pub hash: u64, diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs index 077531587536..f9e90f393219 100644 --- a/src/librustc_incremental/persist/directory.rs +++ b/src/librustc_incremental/persist/directory.rs @@ -64,7 +64,7 @@ impl RetracedDefIdDirectory { pub struct DefIdDirectoryBuilder<'a,'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - hash: DefIdMap>, + hash: DefIdMap, directory: DefIdDirectory, } @@ -77,29 +77,22 @@ impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> { } } - pub fn add(&mut self, def_id: DefId) -> Option { - if !def_id.is_local() { - // FIXME(#32015) clarify story about cross-crate dep tracking - return None; - } - + pub fn add(&mut self, def_id: DefId) -> DefPathIndex { + debug!("DefIdDirectoryBuilder: def_id={:?}", def_id); let tcx = self.tcx; let paths = &mut self.directory.paths; self.hash.entry(def_id) .or_insert_with(|| { let def_path = tcx.def_path(def_id); - if !def_path.is_local() { - return None; - } let index = paths.len() as u32; paths.push(def_path); - Some(DefPathIndex { index: index }) + DefPathIndex { index: index } }) .clone() } - pub fn map(&mut self, node: DepNode) -> Option> { - node.map_def(|&def_id| self.add(def_id)) + pub fn map(&mut self, node: DepNode) -> DepNode { + node.map_def(|&def_id| Some(self.add(def_id))).unwrap() } pub fn into_directory(self) -> DefIdDirectory { diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs new file mode 100644 index 000000000000..c36b9ed0d26a --- /dev/null +++ b/src/librustc_incremental/persist/hash.rs @@ -0,0 +1,158 @@ +// Copyright 2014 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 calculate_svh::SvhCalculate; +use rbml::Error; +use rbml::opaque::Decoder; +use rustc::dep_graph::DepNode; +use rustc::hir::def_id::DefId; +use rustc::hir::svh::Svh; +use rustc::ty::TyCtxt; +use rustc_data_structures::fnv::FnvHashMap; +use rustc_serialize::Decodable; +use std::io::{ErrorKind, Read}; +use std::fs::File; +use syntax::ast; + +use super::data::*; +use super::util::*; + +pub struct HashContext<'a, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + item_metadata_hashes: FnvHashMap, + crate_hashes: FnvHashMap, +} + +impl<'a, 'tcx> HashContext<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + HashContext { + tcx: tcx, + item_metadata_hashes: FnvHashMap(), + crate_hashes: FnvHashMap(), + } + } + + pub fn hash(&mut self, dep_node: DepNode) -> Option { + match dep_node { + // HIR nodes (which always come from our crate) are an input: + DepNode::Hir(def_id) => { + assert!(def_id.is_local()); + Some(self.hir_hash(def_id)) + } + + // MetaData from other crates is an *input* to us. + // MetaData nodes from *our* crates are an *output*; we + // don't hash them, but we do compute a hash for them and + // save it for others to use. + DepNode::MetaData(def_id) if !def_id.is_local() => { + Some(self.metadata_hash(def_id)) + } + + _ => { + // Other kinds of nodes represent computed by-products + // that we don't hash directly; instead, they should + // have some transitive dependency on a Hir or + // MetaData node, so we'll just hash that + None + } + } + } + + fn hir_hash(&mut self, def_id: DefId) -> u64 { + assert!(def_id.is_local()); + // FIXME(#32753) -- should we use a distinct hash here + self.tcx.calculate_item_hash(def_id) + } + + fn metadata_hash(&mut self, def_id: DefId) -> u64 { + debug!("metadata_hash(def_id={:?})", def_id); + + assert!(!def_id.is_local()); + loop { + // check whether we have a result cached for this def-id + if let Some(&hash) = self.item_metadata_hashes.get(&def_id) { + debug!("metadata_hash: def_id={:?} hash={:?}", def_id, hash); + return hash; + } + + // check whether we did not find detailed metadata for this + // krate; in that case, we just use the krate's overall hash + if let Some(&hash) = self.crate_hashes.get(&def_id.krate) { + debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, hash); + return hash.as_u64(); + } + + // otherwise, load the data and repeat. + self.load_data(def_id.krate); + assert!(self.crate_hashes.contains_key(&def_id.krate)); + } + } + + fn load_data(&mut self, cnum: ast::CrateNum) { + debug!("load_data(cnum={})", cnum); + + let svh = self.tcx.sess.cstore.crate_hash(cnum); + let old = self.crate_hashes.insert(cnum, svh); + debug!("load_data: svh={}", svh); + assert!(old.is_none(), "loaded data for crate {:?} twice", cnum); + + if let Some(path) = metadata_hash_path(self.tcx, cnum) { + debug!("load_data: path={:?}", path); + let mut data = vec![]; + match + File::open(&path) + .and_then(|mut file| file.read_to_end(&mut data)) + { + Ok(_) => { + match self.load_from_data(cnum, &data) { + Ok(()) => { } + Err(err) => { + bug!("decoding error in dep-graph from `{}`: {}", + path.display(), err); + } + } + } + Err(err) => { + match err.kind() { + ErrorKind::NotFound => { + // If the file is not found, that's ok. + } + _ => { + self.tcx.sess.err( + &format!("could not load dep information from `{}`: {}", + path.display(), err)); + return; + } + } + } + } + } + } + + fn load_from_data(&mut self, cnum: ast::CrateNum, data: &[u8]) -> Result<(), Error> { + debug!("load_from_data(cnum={})", cnum); + + // Load up the hashes for the def-ids from this crate. + let mut decoder = Decoder::new(data, 0); + let serialized_hashes = try!(SerializedMetadataHashes::decode(&mut decoder)); + for serialized_hash in serialized_hashes.hashes { + // the hashes are stored with just a def-index, which is + // always relative to the old crate; convert that to use + // our internal crate number + let def_id = DefId { krate: cnum, index: serialized_hash.def_index }; + + // record the hash for this dep-node + let old = self.item_metadata_hashes.insert(def_id, serialized_hash.hash); + debug!("load_from_data: def_id={:?} hash={}", def_id, serialized_hash.hash); + assert!(old.is_none(), "already have hash for {:?}", def_id); + } + Ok(()) + } +} diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 35ef0917517c..e3fd290443c1 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -24,6 +24,7 @@ use std::path::Path; use super::data::*; use super::directory::*; use super::dirty_clean; +use super::hash::*; use super::util::*; type DirtyNodes = FnvHashSet>; @@ -133,13 +134,13 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hashes: &[SerializedHash], retraced: &RetracedDefIdDirectory) -> DirtyNodes { + let mut hcx = HashContext::new(tcx); let mut items_removed = false; let mut dirty_nodes = FnvHashSet(); for hash in hashes { match hash.node.map_def(|&i| retraced.def_id(i)) { Some(dep_node) => { - // FIXME(#32753) -- should we use a distinct hash here - let current_hash = dep_node.hash(tcx).unwrap(); + let current_hash = hcx.hash(dep_node).unwrap(); debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}", dep_node, current_hash, hash.hash); if current_hash != hash.hash { diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 8d04fd30a192..72ccc29c97b6 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -15,6 +15,7 @@ mod data; mod directory; mod dirty_clean; +mod hash; mod load; mod save; mod util; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 868f2ee4244a..7deb1ca36dbd 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -20,18 +20,23 @@ use std::path::PathBuf; use super::data::*; use super::directory::*; +use super::hash::*; use super::util::*; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _ignore = tcx.dep_graph.in_ignore(); - - save_in(tcx, dep_graph_path(tcx), encode_dep_graph); - save_in(tcx, metadata_hash_path(tcx, LOCAL_CRATE), encode_metadata_hashes); + let mut hcx = HashContext::new(tcx); + save_in(&mut hcx, dep_graph_path(tcx), encode_dep_graph); + save_in(&mut hcx, metadata_hash_path(tcx, LOCAL_CRATE), encode_metadata_hashes); } -fn save_in<'a,'tcx,F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, opt_path_buf: Option, encode: F) - where F: FnOnce(TyCtxt<'a, 'tcx, 'tcx>, &mut Encoder) -> io::Result<()> +fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>, + opt_path_buf: Option, + encode: F) + where F: FnOnce(&mut HashContext<'a, 'tcx>, &mut Encoder) -> io::Result<()> { + let tcx = hcx.tcx; + let path_buf = match opt_path_buf { Some(p) => p, None => return @@ -54,7 +59,7 @@ fn save_in<'a,'tcx,F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, opt_path_buf: Option // generate the data in a memory buffer let mut wr = Cursor::new(Vec::new()); - match encode(tcx, &mut Encoder::new(&mut wr)) { + match encode(hcx, &mut Encoder::new(&mut wr)) { Ok(()) => { } Err(err) => { tcx.sess.err( @@ -80,9 +85,11 @@ fn save_in<'a,'tcx,F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, opt_path_buf: Option } } -pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>, encoder: &mut Encoder) - -> io::Result<()> { + -> io::Result<()> +{ + let tcx = hcx.tcx; let query = tcx.dep_graph.query(); let mut builder = DefIdDirectoryBuilder::new(tcx); @@ -92,29 +99,24 @@ pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, query.nodes() .into_iter() .filter_map(|dep_node| { - dep_node.hash(tcx) - .map(|hash| { - let node = builder.map(dep_node).unwrap(); - SerializedHash { node: node, hash: hash } - }) + hcx.hash(dep_node) + .map(|hash| { + let node = builder.map(dep_node); + SerializedHash { node: node, hash: hash } + }) }) .collect(); - // Create the serialized dep-graph, dropping nodes that are - // from other crates or from inlined items. - // - // FIXME(#32015) fix handling of other crates + // Create the serialized dep-graph. let graph = SerializedDepGraph { nodes: query.nodes().into_iter() - .flat_map(|node| builder.map(node)) + .map(|node| builder.map(node)) .collect(), edges: query.edges().into_iter() - .flat_map(|(source_node, target_node)| { - builder.map(source_node) - .and_then(|source| { - builder.map(target_node) - .map(|target| (source, target)) - }) + .map(|(source_node, target_node)| { + let source = builder.map(source_node); + let target = builder.map(target_node); + (source, target) }) .collect(), hashes: hashes, @@ -130,14 +132,13 @@ pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } -pub fn encode_metadata_hashes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>, encoder: &mut Encoder) -> io::Result<()> { + let tcx = hcx.tcx; let query = tcx.dep_graph.query(); - let mut builder = DefIdDirectoryBuilder::new(tcx); - let serialized_hashes = { // Identify the `MetaData(X)` nodes where `X` is local. These are // the metadata items we export. Downstream crates will want to @@ -152,32 +153,31 @@ pub fn encode_metadata_hashes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); // To create the hash for each item `X`, we don't hash the raw - // bytes of the metadata (though in principle we could). Instead, - // we walk the predecessors of `MetaData(X)` from the - // dep-graph. This corresponds to all the inputs that were read to - // construct the metadata. To create the hash for the metadata, we - // hash (the hash of) all of those inputs. + // bytes of the metadata (though in principle we + // could). Instead, we walk the predecessors of `MetaData(X)` + // from the dep-graph. This corresponds to all the inputs that + // were read to construct the metadata. To create the hash for + // the metadata, we hash (the hash of) all of those inputs. let hashes = meta_data_def_ids .map(|def_id| { + assert!(def_id.is_local()); + let dep_node = DepNode::MetaData(def_id); let mut state = SipHasher::new(); - for node in query.transitive_predecessors(DepNode::MetaData(def_id)) { - if let Some(hash) = node.hash(tcx) { + debug!("save: computing metadata hash for {:?}", dep_node); + for node in query.transitive_predecessors(dep_node) { + if let Some(hash) = hcx.hash(node) { + debug!("save: predecessor {:?} has hash {}", node, hash); state.write_u64(hash.to_le()); + } else { + debug!("save: predecessor {:?} cannot be hashed", node); } } - (def_id, state.finish()) - }); - - // Now create the `SerializedHash` data structures that others - // will load later. - let hashes = - hashes - .map(|(def_id, hash)| { - let index = builder.add(def_id).unwrap(); - SerializedHash { - node: DepNode::MetaData(index), - hash: hash + let hash = state.finish(); + debug!("save: metadata hash for {:?} is {}", dep_node, hash); + SerializedMetadataHash { + def_index: def_id.index, + hash: hash, } }); @@ -188,8 +188,6 @@ pub fn encode_metadata_hashes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; // Encode everything. - let directory = builder.into_directory(); - try!(directory.encode(encoder)); try!(serialized_hashes.encode(encoder)); Ok(()) diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs index 7acfdb5fffe9..a77a9607e773 100644 --- a/src/librustc_incremental/persist/util.rs +++ b/src/librustc_incremental/persist/util.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use calculate_svh::SvhCalculate; -use rustc::dep_graph::DepNode; -use rustc::hir::def_id::DefId; use rustc::middle::cstore::LOCAL_CRATE; use rustc::ty::TyCtxt; @@ -72,21 +69,3 @@ fn create_dir_racy(path: &Path) -> io::Result<()> { } } -pub trait DepNodeHash { - /// Hash this dep-node, if it is of the kind that we know how to - /// hash. - fn hash<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option; -} - -impl DepNodeHash for DepNode { - fn hash<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { - match *self { - DepNode::Hir(def_id) => { - // FIXME(#32753) -- should we use a distinct hash here - assert!(def_id.is_local()); - Some(tcx.calculate_item_hash(def_id)) - } - _ => None - } - } -} From bed7ea860948775de2d6edeff57c5218c6499af7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 6 May 2016 15:17:55 -0400 Subject: [PATCH 16/21] basic tests for cross-crate hashing --- .../callee_caller_cross_crate/auxiliary/a.rs | 24 +++++++++++++++ .../callee_caller_cross_crate/b.rs | 28 ++++++++++++++++++ .../type_alias_cross_crate/auxiliary/a.rs | 21 ++++++++++++++ .../incremental/type_alias_cross_crate/b.rs | 29 +++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs create mode 100644 src/test/incremental/callee_caller_cross_crate/b.rs create mode 100644 src/test/incremental/type_alias_cross_crate/auxiliary/a.rs create mode 100644 src/test/incremental/type_alias_cross_crate/b.rs diff --git a/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs new file mode 100644 index 000000000000..d802c9a8352e --- /dev/null +++ b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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. + +#![crate_type="rlib"] + +#[cfg(rpass1)] +pub fn function0(x: u32) -> u32 { + x +} + +#[cfg(rpass2)] +pub fn function0(x: i32) -> i32 { + x +} + +pub fn function1(x: u32) { +} diff --git a/src/test/incremental/callee_caller_cross_crate/b.rs b/src/test/incremental/callee_caller_cross_crate/b.rs new file mode 100644 index 000000000000..e81f828beb19 --- /dev/null +++ b/src/test/incremental/callee_caller_cross_crate/b.rs @@ -0,0 +1,28 @@ +// Copyright 2014 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. + +// aux-build:a.rs +// revisions:rpass1 rpass2 + +#![feature(rustc_attrs)] + +extern crate a; + +#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] +pub fn call_function0() { + a::function0(77); +} + +#[rustc_clean(label="TypeckItemBody", cfg="rpass2")] +pub fn call_function1() { + a::function1(77); +} + +pub fn main() { } diff --git a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs new file mode 100644 index 000000000000..2494dca0509b --- /dev/null +++ b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs @@ -0,0 +1,21 @@ +// Copyright 2014 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. + +#![crate_type="rlib"] + +#[cfg(rpass1)] +pub type X = u32; + +#[cfg(rpass2)] +pub type X = i32; + +pub type Y = char; + +pub fn foo() { } diff --git a/src/test/incremental/type_alias_cross_crate/b.rs b/src/test/incremental/type_alias_cross_crate/b.rs new file mode 100644 index 000000000000..b4e9b7601010 --- /dev/null +++ b/src/test/incremental/type_alias_cross_crate/b.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// aux-build:a.rs +// revisions:rpass1 rpass2 + +#![feature(rustc_attrs)] + +extern crate a; + +#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] +pub fn use_X() -> u32 { + let x: a::X = 22; + x as u32 +} + +#[rustc_clean(label="TypeckItemBody", cfg="rpass2")] +pub fn use_Y() { + let x: a::Y = 'c'; +} + +pub fn main() { } From c9810013895914d29b06ba2fa720296035998f35 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 12 May 2016 10:12:58 -0400 Subject: [PATCH 17/21] nit: use format! instead of iterator --- src/librustc/hir/svh.rs | 12 +----------- src/librustc/lib.rs | 1 - 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs index f0294ad633ad..d4e797c9f2d2 100644 --- a/src/librustc/hir/svh.rs +++ b/src/librustc/hir/svh.rs @@ -36,17 +36,7 @@ impl Svh { } pub fn to_string(&self) -> String { - let hash = self.hash; - return (0..64).step_by(4).map(|i| hex(hash >> i)).collect(); - - fn hex(b: u64) -> char { - let b = (b & 0xf) as u8; - let b = match b { - 0 ... 9 => '0' as u8 + b, - _ => 'a' as u8 + b - 10, - }; - b as char - } + format!("{:016x}", self.hash) } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index ed63783366bf..e1fb701e641b 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -37,7 +37,6 @@ #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(staged_api)] -#![feature(step_by)] #![feature(question_mark)] #![cfg_attr(test, feature(test))] From e4c31de61ec1e59c802c67cc62e9a4a164127e7c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 12 May 2016 11:37:08 -0400 Subject: [PATCH 18/21] nit: cache crate-hash for next time --- src/librustc_incremental/persist/hash.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index c36b9ed0d26a..b729f25b873d 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -86,6 +86,11 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { // krate; in that case, we just use the krate's overall hash if let Some(&hash) = self.crate_hashes.get(&def_id.krate) { debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, hash); + + // micro-"optimization": avoid a cache miss if we ask + // for metadata from this particular def-id again. + self.item_metadata_hashes.insert(def_id, hash.as_u64()); + return hash.as_u64(); } From eaafe45c0851fc7027f221dd53f94384ace83124 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 13 May 2016 18:48:46 -0400 Subject: [PATCH 19/21] add debug info to dep_graph --- src/librustc/dep_graph/thread.rs | 3 +++ src/librustc/dep_graph/visit.rs | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs index b15e0e33b840..70d0a4e315c3 100644 --- a/src/librustc/dep_graph/thread.rs +++ b/src/librustc/dep_graph/thread.rs @@ -28,6 +28,7 @@ use super::DepGraphQuery; use super::DepNode; use super::edges::DepGraphEdges; +#[derive(Debug)] pub enum DepMessage { Read(DepNode), Write(DepNode), @@ -117,6 +118,8 @@ impl DepGraphThreadData { /// the buffer is full, this may swap.) #[inline] pub fn enqueue(&self, message: DepMessage) { + debug!("enqueue: {:?} tasks_pushed={}", message, self.tasks_pushed.get()); + // Regardless of whether dep graph construction is enabled, we // still want to check that we always have a valid task on the // stack when a read/write/etc event occurs. diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index 321d109ca0e7..9133b4d22eeb 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -42,7 +42,8 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let _task = self.tcx.dep_graph.in_task(task_id); debug!("Started task {:?}", task_id); self.tcx.dep_graph.read(DepNode::Hir(item_def_id)); - self.visitor.visit_item(i) + self.visitor.visit_item(i); + debug!("Ended task {:?}", task_id); } } From 4d3ef6b63d1f96e3762176fe2246c50b5077517d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 13 May 2016 18:48:54 -0400 Subject: [PATCH 20/21] fix indentation of session/mod.rs --- src/librustc/session/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 61d6acfe061f..907241d1746d 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -628,9 +628,9 @@ pub fn span_bug_fmt>(file: &'static str, } fn opt_span_bug_fmt>(file: &'static str, - line: u32, - span: Option, - args: fmt::Arguments) -> ! { + line: u32, + span: Option, + args: fmt::Arguments) -> ! { tls::with_opt(move |tcx| { let msg = format!("{}:{}: {}", file, line, args); match (tcx, span) { From f860f8b7c9bf32137f5bd929e88925debbcc0b2c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 18 May 2016 09:23:40 -0400 Subject: [PATCH 21/21] add task for linking In MSVC (at least), linking requires accessing metadata, which generates reads. --- src/librustc/dep_graph/dep_node.rs | 2 ++ src/librustc_trans/back/link.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index f2c9d0b12201..84c84a7ed57a 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -81,6 +81,7 @@ pub enum DepNode { TransCrateItem(D), TransInlinedItem(D), TransWriteMetadata, + LinkBinary, // Nodes representing bits of computed IR in the tcx. Each shared // table in the tcx (or elsewhere) maps to one of these @@ -178,6 +179,7 @@ impl DepNode { LateLintCheck => Some(LateLintCheck), TransCrate => Some(TransCrate), TransWriteMetadata => Some(TransWriteMetadata), + LinkBinary => Some(LinkBinary), Hir(ref d) => op(d).map(Hir), MetaData(ref d) => op(d).map(MetaData), CollectItem(ref d) => op(d).map(CollectItem), diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 00d9658cb594..b5248c209a30 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -25,6 +25,7 @@ use middle::dependency_format::Linkage; use CrateTranslation; use util::common::time; use util::fs::fix_windows_verbatim_for_gcc; +use rustc::dep_graph::DepNode; use rustc::ty::TyCtxt; use rustc_back::tempdir::TempDir; @@ -183,6 +184,8 @@ pub fn link_binary(sess: &Session, trans: &CrateTranslation, outputs: &OutputFilenames, crate_name: &str) -> Vec { + let _task = sess.dep_graph.in_task(DepNode::LinkBinary); + let mut out_filenames = Vec::new(); for &crate_type in sess.crate_types.borrow().iter() { if invalid_output_for_target(sess, crate_type) {