]> git.proxmox.com Git - rustc.git/blame - src/librustc/dep_graph/dep_tracking_map.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc / dep_graph / dep_tracking_map.rs
CommitLineData
9cc50fc6
SL
1// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
54a0048b 11use hir::def_id::DefId;
9cc50fc6
SL
12use rustc_data_structures::fnv::FnvHashMap;
13use std::cell::RefCell;
14use std::ops::Index;
15use std::hash::Hash;
16use std::marker::PhantomData;
17use util::common::MemoizationMap;
18
19use super::{DepNode, DepGraph};
20
21/// A DepTrackingMap offers a subset of the `Map` API and ensures that
22/// we make calls to `read` and `write` as appropriate. We key the
23/// maps with a unique type for brevity.
24pub struct DepTrackingMap<M: DepTrackingMapConfig> {
25 phantom: PhantomData<M>,
26 graph: DepGraph,
27 map: FnvHashMap<M::Key, M::Value>,
28}
29
30pub trait DepTrackingMapConfig {
31 type Key: Eq + Hash + Clone;
32 type Value: Clone;
54a0048b 33 fn to_dep_node(key: &Self::Key) -> DepNode<DefId>;
9cc50fc6
SL
34}
35
36impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
37 pub fn new(graph: DepGraph) -> DepTrackingMap<M> {
38 DepTrackingMap {
39 phantom: PhantomData,
40 graph: graph,
41 map: FnvHashMap()
42 }
43 }
44
45 /// Registers a (synthetic) read from the key `k`. Usually this
46 /// is invoked automatically by `get`.
47 fn read(&self, k: &M::Key) {
48 let dep_node = M::to_dep_node(k);
49 self.graph.read(dep_node);
50 }
51
52 /// Registers a (synthetic) write to the key `k`. Usually this is
53 /// invoked automatically by `insert`.
54 fn write(&self, k: &M::Key) {
55 let dep_node = M::to_dep_node(k);
56 self.graph.write(dep_node);
57 }
58
59 pub fn get(&self, k: &M::Key) -> Option<&M::Value> {
60 self.read(k);
61 self.map.get(k)
62 }
63
64 pub fn insert(&mut self, k: M::Key, v: M::Value) -> Option<M::Value> {
65 self.write(&k);
66 self.map.insert(k, v)
67 }
68
69 pub fn contains_key(&self, k: &M::Key) -> bool {
70 self.read(k);
71 self.map.contains_key(k)
72 }
73}
74
75impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
76 type Key = M::Key;
77 type Value = M::Value;
78
79 /// Memoizes an entry in the dep-tracking-map. If the entry is not
80 /// already present, then `op` will be executed to compute its value.
81 /// The resulting dependency graph looks like this:
82 ///
83 /// [op] -> Map(key) -> CurrentTask
84 ///
85 /// Here, `[op]` represents whatever nodes `op` reads in the
86 /// course of execution; `Map(key)` represents the node for this
87 /// map; and `CurrentTask` represents the current task when
88 /// `memoize` is invoked.
89 ///
90 /// **Important:* when `op` is invoked, the current task will be
91 /// switched to `Map(key)`. Therefore, if `op` makes use of any
92 /// HIR nodes or shared state accessed through its closure
93 /// environment, it must explicitly register a read of that
94 /// state. As an example, see `type_scheme_of_item` in `collect`,
95 /// which looks something like this:
96 ///
97 /// ```
98 /// fn type_scheme_of_item(..., item: &hir::Item) -> ty::TypeScheme<'tcx> {
99 /// let item_def_id = ccx.tcx.map.local_def_id(it.id);
100 /// ccx.tcx.tcache.memoized(item_def_id, || {
101 /// ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*)
102 /// compute_type_scheme_of_item(ccx, item)
103 /// });
104 /// }
105 /// ```
106 ///
107 /// The key is the line marked `(*)`: the closure implicitly
108 /// accesses the body of the item `item`, so we register a read
109 /// from `Hir(item_def_id)`.
110 fn memoize<OP>(&self, key: M::Key, op: OP) -> M::Value
111 where OP: FnOnce() -> M::Value
112 {
113 let graph;
114 {
115 let this = self.borrow();
116 if let Some(result) = this.map.get(&key) {
117 this.read(&key);
118 return result.clone();
119 }
120 graph = this.graph.clone();
121 }
122
123 let _task = graph.in_task(M::to_dep_node(&key));
124 let result = op();
125 self.borrow_mut().map.insert(key, result.clone());
126 result
127 }
128}
129
130impl<'k, M: DepTrackingMapConfig> Index<&'k M::Key> for DepTrackingMap<M> {
131 type Output = M::Value;
132
133 #[inline]
134 fn index(&self, k: &'k M::Key) -> &M::Value {
135 self.get(k).unwrap()
136 }
137}
138