]>
git.proxmox.com Git - rustc.git/blob - src/librustc_metadata/index_builder.rs
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.
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.
11 //! Builder types for generating the "item data" section of the
12 //! metadata. This section winds up looking like this:
15 //! <common::data> // big list of item-like things...
16 //! <common::data_item> // ...for most def-ids, there is an entry.
17 //! </common::data_item>
21 //! As we generate this listing, we collect the offset of each
22 //! `data_item` entry and store it in an index. Then, when we load the
23 //! metadata, we can skip right to the metadata for a particular item.
25 //! In addition to the offset, we need to track the data that was used
26 //! to generate the contents of each `data_item`. This is so that we
27 //! can figure out which HIR nodes contributed to that data for
28 //! incremental compilation purposes.
30 //! The `IndexBuilder` facilitates both of these. It is created
31 //! with an `EncodingContext` (`ecx`), which it encapsulates.
32 //! It has one main method, `record()`. You invoke `record`
33 //! like so to create a new `data_item` element in the list:
36 //! index.record(some_def_id, callback_fn, data)
39 //! What record will do is to (a) record the current offset, (b) emit
40 //! the `common::data_item` tag, and then call `callback_fn` with the
41 //! given data as well as the `EncodingContext`. Once `callback_fn`
42 //! returns, the `common::data_item` tag will be closed.
44 //! `EncodingContext` does not offer the `record` method, so that we
45 //! can ensure that `common::data_item` elements are never nested.
47 //! In addition, while the `callback_fn` is executing, we will push a
48 //! task `MetaData(some_def_id)`, which can then observe the
49 //! reads/writes that occur in the task. For this reason, the `data`
50 //! argument that is given to the `callback_fn` must implement the
51 //! trait `DepGraphRead`, which indicates how to register reads on the
52 //! data in this new task (note that many types of data, such as
53 //! `DefId`, do not currently require any reads to be registered,
54 //! since they are not derived from a HIR node). This is also why we
55 //! give a callback fn, rather than taking a closure: it allows us to
56 //! easily control precisely what data is given to that fn.
58 use encoder
::EncodeContext
;
62 use rustc
::dep_graph
::DepNode
;
64 use rustc
::hir
::def_id
::DefId
;
65 use rustc
::ty
::TyCtxt
;
68 use std
::ops
::{Deref, DerefMut}
;
70 /// Builder that can encode new items, adding them into the index.
71 /// Item encoding cannot be nested.
72 pub struct IndexBuilder
<'a
, 'b
: 'a
, 'tcx
: 'b
> {
74 pub ecx
: &'a
mut EncodeContext
<'b
, 'tcx
>,
77 impl<'a
, 'b
, 'tcx
> Deref
for IndexBuilder
<'a
, 'b
, 'tcx
> {
78 type Target
= EncodeContext
<'b
, 'tcx
>;
79 fn deref(&self) -> &Self::Target
{
84 impl<'a
, 'b
, 'tcx
> DerefMut
for IndexBuilder
<'a
, 'b
, 'tcx
> {
85 fn deref_mut(&mut self) -> &mut Self::Target
{
90 impl<'a
, 'b
, 'tcx
> IndexBuilder
<'a
, 'b
, 'tcx
> {
91 pub fn new(ecx
: &'a
mut EncodeContext
<'b
, 'tcx
>) -> Self {
93 items
: Index
::new(ecx
.tcx
.map
.num_local_def_ids()),
98 /// Emit the data for a def-id to the metadata. The function to
99 /// emit the data is `op`, and it will be given `data` as
100 /// arguments. This `record` function will call `op` to generate
101 /// the `Entry` (which may point to other encoded information)
102 /// and will then record the `Lazy<Entry>` for use in the index.
104 /// In addition, it will setup a dep-graph task to track what data
105 /// `op` accesses to generate the metadata, which is later used by
106 /// incremental compilation to compute a hash for the metadata and
109 /// The reason that `op` is a function pointer, and not a closure,
110 /// is that we want to be able to completely track all data it has
111 /// access to, so that we can be sure that `DATA: DepGraphRead`
112 /// holds, and that it is therefore not gaining "secret" access to
113 /// bits of HIR or other state that would not be trackd by the
115 pub fn record
<DATA
>(&mut self,
117 op
: fn(&mut EncodeContext
<'b
, 'tcx
>, DATA
) -> Entry
<'tcx
>,
119 where DATA
: DepGraphRead
121 let _task
= self.tcx
.dep_graph
.in_task(DepNode
::MetaData(id
));
123 let entry
= op(&mut self.ecx
, data
);
124 self.items
.record(id
, self.ecx
.lazy(&entry
));
127 pub fn into_items(self) -> Index
{
132 /// Trait used for data that can be passed from outside a dep-graph
133 /// task. The data must either be of some safe type, such as a
134 /// `DefId` index, or implement the `read` method so that it can add
135 /// a read of whatever dep-graph nodes are appropriate.
136 pub trait DepGraphRead
{
137 fn read(&self, tcx
: TyCtxt
);
140 impl DepGraphRead
for DefId
{
141 fn read(&self, _tcx
: TyCtxt
) { }
144 impl DepGraphRead
for ast
::NodeId
{
145 fn read(&self, _tcx
: TyCtxt
) { }
148 impl<T
> DepGraphRead
for Option
<T
>
149 where T
: DepGraphRead
151 fn read(&self, tcx
: TyCtxt
) {
153 Some(ref v
) => v
.read(tcx
),
159 impl<T
> DepGraphRead
for [T
]
160 where T
: DepGraphRead
162 fn read(&self, tcx
: TyCtxt
) {
169 macro_rules
! read_tuple
{
170 ($
($name
:ident
),*) => {
171 impl<$
($name
),*> DepGraphRead
for ($
($name
),*)
172 where $
($name
: DepGraphRead
),*
174 #[allow(non_snake_case)]
175 fn read(&self, tcx
: TyCtxt
) {
176 let &($
(ref $name
),*) = self;
185 macro_rules
! read_hir
{
187 impl<'tcx
> DepGraphRead
for &'tcx $t
{
188 fn read(&self, tcx
: TyCtxt
) {
189 tcx
.map
.read(self.id
);
194 read_hir
!(hir
::Item
);
195 read_hir
!(hir
::ImplItem
);
196 read_hir
!(hir
::TraitItem
);
197 read_hir
!(hir
::ForeignItem
);
199 /// Leaks access to a value of type T without any tracking. This is
200 /// suitable for ambiguous types like `usize`, which *could* represent
201 /// tracked data (e.g., if you read it out of a HIR node) or might not
202 /// (e.g., if it's an index). Adding in an `Untracked` is an
203 /// assertion, essentially, that the data does not need to be tracked
204 /// (or that read edges will be added by some other way).
206 /// A good idea is to add to each use of `Untracked` an explanation of
207 /// why this value is ok.
208 pub struct Untracked
<T
>(pub T
);
210 impl<T
> DepGraphRead
for Untracked
<T
> {
211 fn read(&self, _tcx
: TyCtxt
) { }
214 /// Newtype that can be used to package up misc data extracted from a
215 /// HIR node that doesn't carry its own id. This will allow an
216 /// arbitrary `T` to be passed in, but register a read on the given
218 pub struct FromId
<T
>(pub ast
::NodeId
, pub T
);
220 impl<T
> DepGraphRead
for FromId
<T
> {
221 fn read(&self, tcx
: TyCtxt
) {
222 tcx
.map
.read(self.0);