Instrument the AST map so that it registers reads when data is

acccessed.
This commit is contained in:
Niko Matsakis 2016-01-29 15:07:04 -05:00
parent 37fbfaf183
commit d09fd1a529
8 changed files with 118 additions and 18 deletions

View File

@ -116,6 +116,13 @@ impl DepGraph {
}
}
/// True if we are actually building a dep-graph. If this returns false,
/// then the other methods on this `DepGraph` will have no net effect.
#[inline]
pub fn enabled(&self) -> bool {
self.data.enabled()
}
pub fn query(&self) -> DepGraphQuery {
self.data.query()
}

View File

@ -79,6 +79,7 @@ impl<'ast> NodeCollector<'ast> {
fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex {
let parent_def = self.parent_def();
debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
self.definitions.create_def_with_parent(parent_def, node_id, data)
}
@ -115,10 +116,13 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
/// deep walking so that we walk nested items in the context of
/// their outer items.
fn visit_nested_item(&mut self, item: ItemId) {
debug!("visit_nested_item: {:?}", item);
self.visit_item(self.krate.item(item.id))
}
fn visit_item(&mut self, i: &'ast Item) {
debug!("visit_item: {:?}", i);
// Pick the def data. This need not be unique, but the more
// information we encapsulate into
let def_data = match i.node {

View File

@ -14,6 +14,8 @@ use self::MapEntry::*;
use self::collector::NodeCollector;
pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData};
use dep_graph::{DepGraph, DepNode};
use middle::cstore::InlinedItem;
use middle::cstore::InlinedItem as II;
use middle::def_id::DefId;
@ -228,19 +230,22 @@ impl<'ast> MapEntry<'ast> {
/// Stores a crate and any number of inlined items from other crates.
pub struct Forest {
pub krate: Crate,
krate: Crate,
pub dep_graph: DepGraph,
inlined_items: TypedArena<InlinedParent>
}
impl Forest {
pub fn new(krate: Crate) -> Forest {
pub fn new(krate: Crate, dep_graph: DepGraph) -> Forest {
Forest {
krate: krate,
dep_graph: dep_graph,
inlined_items: TypedArena::new()
}
}
pub fn krate<'ast>(&'ast self) -> &'ast Crate {
self.dep_graph.read(DepNode::Krate);
&self.krate
}
}
@ -252,6 +257,10 @@ pub struct Map<'ast> {
/// The backing storage for all the AST nodes.
pub forest: &'ast Forest,
/// Same as the dep_graph in forest, just available with one fewer
/// deref. This is a gratuitious micro-optimization.
pub dep_graph: DepGraph,
/// NodeIds are sequential integers from 0, so we can be
/// super-compact by storing them in a vector. Not everything with
/// a NodeId is in the map, but empirically the occupancy is about
@ -267,6 +276,60 @@ pub struct Map<'ast> {
}
impl<'ast> Map<'ast> {
/// Registers a read in the dependency graph of the AST node with
/// the given `id`. This needs to be called each time a public
/// function returns the HIR for a node -- in other words, when it
/// "reveals" the content of a node to the caller (who might not
/// otherwise have had access to those contents, and hence needs a
/// read recorded). If the function just returns a DefId or
/// NodeId, no actual content was returned, so no read is needed.
fn read(&self, id: NodeId) {
self.dep_graph.read(self.dep_node(id));
}
fn dep_node(&self, id0: NodeId) -> DepNode {
let map = self.map.borrow();
let mut id = id0;
loop {
match map[id as usize] {
EntryItem(_, item) => {
let def_id = self.local_def_id(item.id);
// NB ^~~~~~~
//
// You would expect that `item.id == id`, but this
// is not always the case. In particular, for
// ViewPath like `use self::{mem, foo}`, we record
// map the ids for `mem` and `foo` to the
// enclosing view path item. This seems mega super
// ultra wrong, but then who am I to
// judge. -nmatsakis
return DepNode::Hir(def_id);
}
EntryForeignItem(p, _) |
EntryTraitItem(p, _) |
EntryImplItem(p, _) |
EntryVariant(p, _) |
EntryExpr(p, _) |
EntryStmt(p, _) |
EntryLocal(p, _) |
EntryPat(p, _) |
EntryBlock(p, _) |
EntryStructCtor(p, _) |
EntryLifetime(p, _) |
EntryTyParam(p, _) =>
id = p,
RootCrate |
RootInlinedParent(_) => // FIXME(#2369) clarify story about cross-crate dep tracking
return DepNode::Krate,
NotPresent =>
panic!("Walking parents from `{}` led to `NotPresent` at `{}`", id0, id),
}
}
}
pub fn num_local_def_ids(&self) -> usize {
self.definitions.borrow().len()
}
@ -309,26 +372,30 @@ impl<'ast> Map<'ast> {
}
pub fn krate(&self) -> &'ast Crate {
&self.forest.krate
self.forest.krate()
}
/// Retrieve the Node corresponding to `id`, panicking if it cannot
/// be found.
pub fn get(&self, id: NodeId) -> Node<'ast> {
match self.find(id) {
Some(node) => node,
Some(node) => node, // read recorded by `find`
None => panic!("couldn't find node id {} in the AST map", id)
}
}
pub fn get_if_local(&self, id: DefId) -> Option<Node<'ast>> {
self.as_local_node_id(id).map(|id| self.get(id))
self.as_local_node_id(id).map(|id| self.get(id)) // read recorded by `get`
}
/// Retrieve the Node corresponding to `id`, returning None if
/// cannot be found.
pub fn find(&self, id: NodeId) -> Option<Node<'ast>> {
self.find_entry(id).and_then(|x| x.to_node())
let result = self.find_entry(id).and_then(|x| x.to_node());
if result.is_some() {
self.read(id);
}
result
}
/// Similar to get_parent, returns the parent node id or id if there is no
@ -459,22 +526,25 @@ impl<'ast> Map<'ast> {
_ => None
};
match abi {
Some(abi) => abi,
Some(abi) => {
self.read(id); // reveals some of the content of a node
abi
}
None => panic!("expected foreign mod or inlined parent, found {}",
self.node_to_string(parent))
}
}
pub fn get_foreign_vis(&self, id: NodeId) -> Visibility {
let vis = self.expect_foreign_item(id).vis;
match self.find(self.get_parent(id)) {
let vis = self.expect_foreign_item(id).vis; // read recorded by `expect_foreign_item`
match self.find(self.get_parent(id)) { // read recorded by `find`
Some(NodeItem(i)) => vis.inherit_from(i.vis),
_ => vis
}
}
pub fn expect_item(&self, id: NodeId) -> &'ast Item {
match self.find(id) {
match self.find(id) { // read recorded by `id`
Some(NodeItem(item)) => item,
_ => panic!("expected item, found {}", self.node_to_string(id))
}
@ -521,7 +591,7 @@ impl<'ast> Map<'ast> {
}
pub fn expect_expr(&self, id: NodeId) -> &'ast Expr {
match self.find(id) {
match self.find(id) { // read recorded by find
Some(NodeExpr(expr)) => expr,
_ => panic!("expected expr, found {}", self.node_to_string(id))
}
@ -571,6 +641,11 @@ impl<'ast> Map<'ast> {
fn with_path_next<T, F>(&self, id: NodeId, next: LinkedPath, f: F) -> T where
F: FnOnce(PathElems) -> T,
{
// This function reveals the name of the item and hence is a
// kind of read. This is inefficient, since it walks ancestors
// and we are walking them anyhow, but whatever.
self.read(id);
let parent = self.get_parent(id);
let parent = match self.find_entry(id) {
Some(EntryForeignItem(..)) => {
@ -602,6 +677,7 @@ impl<'ast> Map<'ast> {
/// Given a node ID, get a list of attributes associated with the AST
/// corresponding to the Node ID
pub fn attrs(&self, id: NodeId) -> &'ast [ast::Attribute] {
self.read(id); // reveals attributes on the node
let attrs = match self.find(id) {
Some(NodeItem(i)) => Some(&i.attrs[..]),
Some(NodeForeignItem(fi)) => Some(&fi.attrs[..]),
@ -655,6 +731,7 @@ impl<'ast> Map<'ast> {
}
pub fn span(&self, id: NodeId) -> Span {
self.read(id); // reveals span from node
self.opt_span(id)
.unwrap_or_else(|| panic!("AstMap.span: could not find span for id {:?}", id))
}
@ -833,6 +910,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
Map {
forest: forest,
dep_graph: forest.dep_graph.clone(),
map: RefCell::new(map),
definitions: RefCell::new(definitions),
}

View File

@ -509,7 +509,7 @@ impl<'tcx> ctxt<'tcx> {
{
let interner = RefCell::new(FnvHashMap());
let common_types = CommonTypes::new(&arenas.type_, &interner);
let dep_graph = DepGraph::new(s.opts.incremental_compilation);
let dep_graph = map.dep_graph.clone();
let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone());
tls::enter(ctxt {
arenas: arenas,

View File

@ -137,8 +137,13 @@ pub struct Options {
pub no_trans: bool,
pub error_format: ErrorOutputType,
pub treat_err_as_bug: bool,
pub incremental_compilation: bool,
/// if true, build up the dep-graph
pub build_dep_graph: bool,
/// if true, -Z dump-dep-graph was passed to dump out the dep-graph
pub dump_dep_graph: bool,
pub no_analysis: bool,
pub debugging_opts: DebuggingOptions,
pub prints: Vec<PrintRequest>,
@ -246,7 +251,7 @@ pub fn basic_options() -> Options {
parse_only: false,
no_trans: false,
treat_err_as_bug: false,
incremental_compilation: false,
build_dep_graph: false,
dump_dep_graph: false,
no_analysis: false,
debugging_opts: basic_debugging_options(),
@ -1145,7 +1150,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
parse_only: parse_only,
no_trans: no_trans,
treat_err_as_bug: treat_err_as_bug,
incremental_compilation: incremental_compilation || dump_dep_graph,
build_dep_graph: incremental_compilation || dump_dep_graph,
dump_dep_graph: dump_dep_graph,
no_analysis: no_analysis,
debugging_opts: debugging_opts,

View File

@ -11,6 +11,7 @@ pub use self::MaybeTyped::*;
use rustc_lint;
use rustc_driver::{driver, target_features, abort_on_err};
use rustc::dep_graph::DepGraph;
use rustc::session::{self, config};
use rustc::middle::def_id::DefId;
use rustc::middle::privacy::AccessLevels;
@ -143,7 +144,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
let krate = driver::assign_node_ids(&sess, krate);
// Lower ast -> hir.
let lcx = LoweringContext::new(&sess, Some(&krate));
let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate));
let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), DepGraph::new(false));
let arenas = ty::CtxtArenas::new();
let hir_map = driver::make_map(&sess, &mut hir_forest);

View File

@ -25,6 +25,7 @@ use std::sync::{Arc, Mutex};
use testing;
use rustc_lint;
use rustc::dep_graph::DepGraph;
use rustc::front::map as hir_map;
use rustc::session::{self, config};
use rustc::session::config::{get_unstable_features_setting, OutputType};
@ -99,7 +100,9 @@ pub fn run(input: &str,
let opts = scrape_test_config(&krate);
let mut forest = hir_map::Forest::new(krate);
let dep_graph = DepGraph::new(false);
let _ignore = dep_graph.in_ignore();
let mut forest = hir_map::Forest::new(krate, dep_graph.clone());
let map = hir_map::map_crate(&mut forest);
let ctx = core::DocContext {

View File

@ -26,6 +26,7 @@ use std::path::PathBuf;
use std::rc::Rc;
use std::thread::Builder;
use rustc::dep_graph::DepGraph;
use rustc::front::map as ast_map;
use rustc::llvm;
use rustc::middle::cstore::{CrateStore, LinkagePreference};
@ -236,7 +237,8 @@ fn compile_program(input: &str, sysroot: PathBuf)
let krate = driver::assign_node_ids(&sess, krate);
let lcx = LoweringContext::new(&sess, Some(&krate));
let mut hir_forest = ast_map::Forest::new(lower_crate(&lcx, &krate));
let dep_graph = DepGraph::new(sess.opts.build_dep_graph);
let mut hir_forest = ast_map::Forest::new(lower_crate(&lcx, &krate), dep_graph);
let arenas = ty::CtxtArenas::new();
let ast_map = driver::make_map(&sess, &mut hir_forest);