Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

incr.comp.: Introduce the concept of anonymous DepNodes and use them for trait selection #42769

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 22 additions & 65 deletions src/librustc/dep_graph/dep_tracking_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,61 +12,35 @@ use rustc_data_structures::fx::FxHashMap;
use std::cell::RefCell;
use std::hash::Hash;
use std::marker::PhantomData;
use ty::TyCtxt;
use util::common::MemoizationMap;

use super::{DepNode, DepGraph};
use super::{DepNode, DepGraph, DepKind};

/// A DepTrackingMap offers a subset of the `Map` API and ensures that
/// we make calls to `read` and `write` as appropriate. We key the
/// maps with a unique type for brevity.
pub struct DepTrackingMap<M: DepTrackingMapConfig> {
phantom: PhantomData<M>,
graph: DepGraph,
map: FxHashMap<M::Key, M::Value>,
map: RefCell<FxHashMap<M::Key, (M::Value, DepNode)>>,
}

pub trait DepTrackingMapConfig {
type Key: Eq + Hash + Clone;
type Value: Clone;
fn to_dep_node(tcx: TyCtxt, key: &Self::Key) -> DepNode;

/// A DepTrackingMap always creates anonymous DepNodes, but the DepKind of
/// the nodes generated by a given map can be specified via this constant.
const DEP_KIND: DepKind;
}

impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
pub fn new(graph: DepGraph) -> DepTrackingMap<M> {
DepTrackingMap {
phantom: PhantomData,
graph: graph,
map: FxHashMap(),
map: RefCell::new(FxHashMap()),
}
}

/// Registers a (synthetic) read from the key `k`. Usually this
/// is invoked automatically by `get`.
fn read(&self, tcx: TyCtxt, k: &M::Key) {
let dep_node = M::to_dep_node(tcx, k);
self.graph.read(dep_node);
}

pub fn get(&self, tcx: TyCtxt, k: &M::Key) -> Option<&M::Value> {
self.read(tcx, k);
self.map.get(k)
}

pub fn contains_key(&self, tcx: TyCtxt, k: &M::Key) -> bool {
self.read(tcx, k);
self.map.contains_key(k)
}

pub fn keys(&self) -> Vec<M::Key> {
self.map.keys().cloned().collect()
}
}

impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
type Key = M::Key;
type Value = M::Value;

/// Memoizes an entry in the dep-tracking-map. If the entry is not
/// already present, then `op` will be executed to compute its value.
/// The resulting dependency graph looks like this:
Expand All @@ -76,44 +50,27 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
/// Here, `[op]` represents whatever nodes `op` reads in the
/// course of execution; `Map(key)` represents the node for this
/// map; and `CurrentTask` represents the current task when
/// `memoize` is invoked.
///
/// **Important:* when `op` is invoked, the current task will be
/// switched to `Map(key)`. Therefore, if `op` makes use of any
/// HIR nodes or shared state accessed through its closure
/// environment, it must explicitly register a read of that
/// state. As an example, see `type_of_item` in `collect`,
/// which looks something like this:
///
/// ```
/// fn type_of_item(..., item: &hir::Item) -> Ty<'tcx> {
/// let item_def_id = ccx.tcx.hir.local_def_id(it.id);
/// ccx.tcx.item_types.memoized(item_def_id, || {
/// ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*)
/// compute_type_of_item(ccx, item)
/// });
/// }
/// ```
///
/// The key is the line marked `(*)`: the closure implicitly
/// accesses the body of the item `item`, so we register a read
/// from `Hir(item_def_id)`.
fn memoize<OP>(&self, tcx: TyCtxt, key: M::Key, op: OP) -> M::Value
where OP: FnOnce() -> M::Value
/// `memoize` is invoked. The node `Map(key)` is an automatically
/// generated, "anonymous" node with DepKind as configured in the
/// map's `DepTrackingMapConfig`.
pub fn memoize<F>(&self,
key: M::Key,
op: F)
-> M::Value
where F: FnOnce() -> M::Value
{
let graph;
{
let this = self.borrow();
if let Some(result) = this.map.get(&key) {
this.read(tcx, &key);
let map = self.map.borrow();
if let Some(&(ref result, dep_node)) = map.get(&key) {
self.graph.read(dep_node);
return result.clone();
}
graph = this.graph.clone();
}

let _task = graph.in_task(M::to_dep_node(tcx, &key));
let result = op();
self.borrow_mut().map.insert(key, result.clone());
let (result, dep_node) = self.graph.with_anon_task(M::DEP_KIND, op);

self.graph.read(dep_node);
self.map.borrow_mut().insert(key, (result.clone(), dep_node));
result
}
}
Loading