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