]> git.lizzy.rs Git - rust.git/blob - src/librustc/metadata/cstore.rs
Convert DefId to use DefIndex, which is an index into a list of
[rust.git] / src / librustc / metadata / cstore.rs
1 // Copyright 2012-2014 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
11 #![allow(non_camel_case_types)]
12
13 // The crate store - a central repo for information collected about external
14 // crates and libraries
15
16 pub use self::MetadataBlob::*;
17 pub use self::LinkagePreference::*;
18 pub use self::NativeLibraryKind::*;
19
20 use back::svh::Svh;
21 use metadata::{creader, decoder, index, loader};
22 use session::search_paths::PathKind;
23 use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
24
25 use std::cell::{RefCell, Ref, Cell};
26 use std::rc::Rc;
27 use std::path::PathBuf;
28 use flate::Bytes;
29 use syntax::ast;
30 use syntax::attr;
31 use syntax::codemap;
32 use syntax::parse::token;
33 use syntax::parse::token::IdentInterner;
34 use syntax::util::small_vector::SmallVector;
35 use front::map as ast_map;
36
37 // A map from external crate numbers (as decoded from some crate file) to
38 // local crate numbers (as generated during this session). Each external
39 // crate may refer to types in other external crates, and each has their
40 // own crate numbers.
41 pub type cnum_map = FnvHashMap<ast::CrateNum, ast::CrateNum>;
42
43 pub enum MetadataBlob {
44     MetadataVec(Bytes),
45     MetadataArchive(loader::ArchiveMetadata),
46 }
47
48 /// Holds information about a codemap::FileMap imported from another crate.
49 /// See creader::import_codemap() for more information.
50 pub struct ImportedFileMap {
51     /// This FileMap's byte-offset within the codemap of its original crate
52     pub original_start_pos: codemap::BytePos,
53     /// The end of this FileMap within the codemap of its original crate
54     pub original_end_pos: codemap::BytePos,
55     /// The imported FileMap's representation within the local codemap
56     pub translated_filemap: Rc<codemap::FileMap>
57 }
58
59 pub struct crate_metadata {
60     pub name: String,
61     pub local_path: RefCell<SmallVector<ast_map::PathElem>>,
62     pub local_def_path: RefCell<ast_map::DefPath>,
63     pub data: MetadataBlob,
64     pub cnum_map: RefCell<cnum_map>,
65     pub cnum: ast::CrateNum,
66     pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
67     pub span: codemap::Span,
68     pub staged_api: bool,
69     pub index: index::Index,
70
71     /// Flag if this crate is required by an rlib version of this crate, or in
72     /// other words whether it was explicitly linked to. An example of a crate
73     /// where this is false is when an allocator crate is injected into the
74     /// dependency list, and therefore isn't actually needed to link an rlib.
75     pub explicitly_linked: Cell<bool>,
76 }
77
78 #[derive(Copy, Debug, PartialEq, Clone)]
79 pub enum LinkagePreference {
80     RequireDynamic,
81     RequireStatic,
82 }
83
84 enum_from_u32! {
85     #[derive(Copy, Clone, PartialEq)]
86     pub enum NativeLibraryKind {
87         NativeStatic,    // native static library (.a archive)
88         NativeFramework, // OSX-specific
89         NativeUnknown,   // default way to specify a dynamic library
90     }
91 }
92
93 // Where a crate came from on the local filesystem. One of these two options
94 // must be non-None.
95 #[derive(PartialEq, Clone)]
96 pub struct CrateSource {
97     pub dylib: Option<(PathBuf, PathKind)>,
98     pub rlib: Option<(PathBuf, PathKind)>,
99     pub cnum: ast::CrateNum,
100 }
101
102 pub struct CStore {
103     metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>,
104     /// Map from NodeId's of local extern crate statements to crate numbers
105     extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>,
106     used_crate_sources: RefCell<Vec<CrateSource>>,
107     used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
108     used_link_args: RefCell<Vec<String>>,
109     statically_included_foreign_items: RefCell<NodeSet>,
110     pub intr: Rc<IdentInterner>,
111 }
112
113 /// Item definitions in the currently-compiled crate would have the CrateNum
114 /// LOCAL_CRATE in their DefId.
115 pub const LOCAL_CRATE: ast::CrateNum = 0;
116
117 impl CStore {
118     pub fn new(intr: Rc<IdentInterner>) -> CStore {
119         CStore {
120             metas: RefCell::new(FnvHashMap()),
121             extern_mod_crate_map: RefCell::new(FnvHashMap()),
122             used_crate_sources: RefCell::new(Vec::new()),
123             used_libraries: RefCell::new(Vec::new()),
124             used_link_args: RefCell::new(Vec::new()),
125             intr: intr,
126             statically_included_foreign_items: RefCell::new(NodeSet()),
127         }
128     }
129
130     pub fn next_crate_num(&self) -> ast::CrateNum {
131         self.metas.borrow().len() as ast::CrateNum + 1
132     }
133
134     pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<crate_metadata> {
135         self.metas.borrow().get(&cnum).unwrap().clone()
136     }
137
138     pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh {
139         let cdata = self.get_crate_data(cnum);
140         decoder::get_crate_hash(cdata.data())
141     }
142
143     pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<crate_metadata>) {
144         self.metas.borrow_mut().insert(cnum, data);
145     }
146
147     pub fn iter_crate_data<I>(&self, mut i: I) where
148         I: FnMut(ast::CrateNum, &Rc<crate_metadata>),
149     {
150         for (&k, v) in self.metas.borrow().iter() {
151             i(k, v);
152         }
153     }
154
155     /// Like `iter_crate_data`, but passes source paths (if available) as well.
156     pub fn iter_crate_data_origins<I>(&self, mut i: I) where
157         I: FnMut(ast::CrateNum, &crate_metadata, Option<CrateSource>),
158     {
159         for (&k, v) in self.metas.borrow().iter() {
160             let origin = self.get_used_crate_source(k);
161             origin.as_ref().map(|cs| { assert!(k == cs.cnum); });
162             i(k, &**v, origin);
163         }
164     }
165
166     pub fn add_used_crate_source(&self, src: CrateSource) {
167         let mut used_crate_sources = self.used_crate_sources.borrow_mut();
168         if !used_crate_sources.contains(&src) {
169             used_crate_sources.push(src);
170         }
171     }
172
173     pub fn get_used_crate_source(&self, cnum: ast::CrateNum)
174                                      -> Option<CrateSource> {
175         self.used_crate_sources.borrow_mut()
176             .iter().find(|source| source.cnum == cnum).cloned()
177     }
178
179     pub fn reset(&self) {
180         self.metas.borrow_mut().clear();
181         self.extern_mod_crate_map.borrow_mut().clear();
182         self.used_crate_sources.borrow_mut().clear();
183         self.used_libraries.borrow_mut().clear();
184         self.used_link_args.borrow_mut().clear();
185         self.statically_included_foreign_items.borrow_mut().clear();
186     }
187
188     // This method is used when generating the command line to pass through to
189     // system linker. The linker expects undefined symbols on the left of the
190     // command line to be defined in libraries on the right, not the other way
191     // around. For more info, see some comments in the add_used_library function
192     // below.
193     //
194     // In order to get this left-to-right dependency ordering, we perform a
195     // topological sort of all crates putting the leaves at the right-most
196     // positions.
197     pub fn get_used_crates(&self, prefer: LinkagePreference)
198                            -> Vec<(ast::CrateNum, Option<PathBuf>)> {
199         let mut ordering = Vec::new();
200         fn visit(cstore: &CStore, cnum: ast::CrateNum,
201                  ordering: &mut Vec<ast::CrateNum>) {
202             if ordering.contains(&cnum) { return }
203             let meta = cstore.get_crate_data(cnum);
204             for (_, &dep) in meta.cnum_map.borrow().iter() {
205                 visit(cstore, dep, ordering);
206             }
207             ordering.push(cnum);
208         };
209         for (&num, _) in self.metas.borrow().iter() {
210             visit(self, num, &mut ordering);
211         }
212         info!("topological ordering: {:?}", ordering);
213         ordering.reverse();
214         let mut libs = self.used_crate_sources.borrow()
215             .iter()
216             .map(|src| (src.cnum, match prefer {
217                 RequireDynamic => src.dylib.clone().map(|p| p.0),
218                 RequireStatic => src.rlib.clone().map(|p| p.0),
219             }))
220             .collect::<Vec<_>>();
221         libs.sort_by(|&(a, _), &(b, _)| {
222             let a = ordering.iter().position(|x| *x == a);
223             let b = ordering.iter().position(|x| *x == b);
224             a.cmp(&b)
225         });
226         libs
227     }
228
229     pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) {
230         assert!(!lib.is_empty());
231         self.used_libraries.borrow_mut().push((lib, kind));
232     }
233
234     pub fn get_used_libraries<'a>(&'a self)
235                               -> &'a RefCell<Vec<(String,
236                                                   NativeLibraryKind)>> {
237         &self.used_libraries
238     }
239
240     pub fn add_used_link_args(&self, args: &str) {
241         for s in args.split(' ').filter(|s| !s.is_empty()) {
242             self.used_link_args.borrow_mut().push(s.to_string());
243         }
244     }
245
246     pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell<Vec<String> > {
247         &self.used_link_args
248     }
249
250     pub fn add_extern_mod_stmt_cnum(&self,
251                                     emod_id: ast::NodeId,
252                                     cnum: ast::CrateNum) {
253         self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
254     }
255
256     pub fn find_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId)
257                                      -> Option<ast::CrateNum> {
258         self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
259     }
260
261     pub fn add_statically_included_foreign_item(&self, id: ast::NodeId) {
262         self.statically_included_foreign_items.borrow_mut().insert(id);
263     }
264
265     pub fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool {
266         self.statically_included_foreign_items.borrow().contains(&id)
267     }
268 }
269
270 impl crate_metadata {
271     pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
272     pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
273     pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
274     pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap)
275                                  -> Ref<'a, Vec<ImportedFileMap>> {
276         let filemaps = self.codemap_import_info.borrow();
277         if filemaps.is_empty() {
278             drop(filemaps);
279             let filemaps = creader::import_codemap(codemap, &self.data);
280
281             // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
282             *self.codemap_import_info.borrow_mut() = filemaps;
283             self.codemap_import_info.borrow()
284         } else {
285             filemaps
286         }
287     }
288
289     pub fn with_local_path<T, F>(&self, f: F) -> T
290         where F: Fn(&[ast_map::PathElem]) -> T
291     {
292         let cpath = self.local_path.borrow();
293         if cpath.is_empty() {
294             let name = ast_map::PathMod(token::intern(&self.name));
295             f(&[name])
296         } else {
297             f(cpath.as_slice())
298         }
299     }
300
301     pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) {
302         let mut cpath = self.local_path.borrow_mut();
303         let cap = cpath.len();
304         match cap {
305             0 => *cpath = candidate.collect(),
306             1 => (),
307             _ => {
308                 let candidate: SmallVector<_> = candidate.collect();
309                 if candidate.len() < cap {
310                     *cpath = candidate;
311                 }
312             },
313         }
314     }
315
316     pub fn local_def_path(&self) -> ast_map::DefPath {
317         let local_def_path = self.local_def_path.borrow();
318         if local_def_path.is_empty() {
319             let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name));
320             vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }]
321         } else {
322             local_def_path.clone()
323         }
324     }
325
326     pub fn update_local_def_path(&self, candidate: ast_map::DefPath) {
327         let mut local_def_path = self.local_def_path.borrow_mut();
328         if local_def_path.is_empty() || candidate.len() < local_def_path.len() {
329             *local_def_path = candidate;
330         }
331     }
332
333     pub fn is_allocator(&self) -> bool {
334         let attrs = decoder::get_crate_attributes(self.data());
335         attr::contains_name(&attrs, "allocator")
336     }
337
338     pub fn needs_allocator(&self) -> bool {
339         let attrs = decoder::get_crate_attributes(self.data());
340         attr::contains_name(&attrs, "needs_allocator")
341     }
342 }
343
344 impl MetadataBlob {
345     pub fn as_slice<'a>(&'a self) -> &'a [u8] {
346         let slice = match *self {
347             MetadataVec(ref vec) => &vec[..],
348             MetadataArchive(ref ar) => ar.as_slice(),
349         };
350         if slice.len() < 4 {
351             &[] // corrupt metadata
352         } else {
353             let len = (((slice[0] as u32) << 24) |
354                        ((slice[1] as u32) << 16) |
355                        ((slice[2] as u32) << 8) |
356                        ((slice[3] as u32) << 0)) as usize;
357             if len + 4 <= slice.len() {
358                 &slice[4.. len + 4]
359             } else {
360                 &[] // corrupt or old metadata
361             }
362         }
363     }
364 }