]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/back/symbol_names.rs
6edf8db9bf7e67534c2b82c4d7febbdfbcb1170b
[rust.git] / src / librustc_trans / back / symbol_names.rs
1 // Copyright 2016 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 //! The Rust Linkage Model and Symbol Names
12 //! =======================================
13 //!
14 //! The semantic model of Rust linkage is, broadly, that "there's no global
15 //! namespace" between crates. Our aim is to preserve the illusion of this
16 //! model despite the fact that it's not *quite* possible to implement on
17 //! modern linkers. We initially didn't use system linkers at all, but have
18 //! been convinced of their utility.
19 //!
20 //! There are a few issues to handle:
21 //!
22 //!  - Linkers operate on a flat namespace, so we have to flatten names.
23 //!    We do this using the C++ namespace-mangling technique. Foo::bar
24 //!    symbols and such.
25 //!
26 //!  - Symbols for distinct items with the same *name* need to get different
27 //!    linkage-names. Examples of this are monomorphizations of functions or
28 //!    items within anonymous scopes that end up having the same path.
29 //!
30 //!  - Symbols in different crates but with same names "within" the crate need
31 //!    to get different linkage-names.
32 //!
33 //!  - Symbol names should be deterministic: Two consecutive runs of the
34 //!    compiler over the same code base should produce the same symbol names for
35 //!    the same items.
36 //!
37 //!  - Symbol names should not depend on any global properties of the code base,
38 //!    so that small modifications to the code base do not result in all symbols
39 //!    changing. In previous versions of the compiler, symbol names incorporated
40 //!    the SVH (Stable Version Hash) of the crate. This scheme turned out to be
41 //!    infeasible when used in conjunction with incremental compilation because
42 //!    small code changes would invalidate all symbols generated previously.
43 //!
44 //!  - Even symbols from different versions of the same crate should be able to
45 //!    live next to each other without conflict.
46 //!
47 //! In order to fulfill the above requirements the following scheme is used by
48 //! the compiler:
49 //!
50 //! The main tool for avoiding naming conflicts is the incorporation of a 64-bit
51 //! hash value into every exported symbol name. Anything that makes a difference
52 //! to the symbol being named, but does not show up in the regular path needs to
53 //! be fed into this hash:
54 //!
55 //! - Different monomorphizations of the same item have the same path but differ
56 //!   in their concrete type parameters, so these parameters are part of the
57 //!   data being digested for the symbol hash.
58 //!
59 //! - Rust allows items to be defined in anonymous scopes, such as in
60 //!   `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have
61 //!   the path `foo::bar`, since the anonymous scopes do not contribute to the
62 //!   path of an item. The compiler already handles this case via so-called
63 //!   disambiguating `DefPaths` which use indices to distinguish items with the
64 //!   same name. The DefPaths of the functions above are thus `foo[0]::bar[0]`
65 //!   and `foo[0]::bar[1]`. In order to incorporate this disambiguation
66 //!   information into the symbol name too, these indices are fed into the
67 //!   symbol hash, so that the above two symbols would end up with different
68 //!   hash values.
69 //!
70 //! The two measures described above suffice to avoid intra-crate conflicts. In
71 //! order to also avoid inter-crate conflicts two more measures are taken:
72 //!
73 //! - The name of the crate containing the symbol is prepended to the symbol
74 //!   name, i.e. symbols are "crate qualified". For example, a function `foo` in
75 //!   module `bar` in crate `baz` would get a symbol name like
76 //!   `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids
77 //!   simple conflicts between functions from different crates.
78 //!
79 //! - In order to be able to also use symbols from two versions of the same
80 //!   crate (which naturally also have the same name), a stronger measure is
81 //!   required: The compiler accepts an arbitrary "disambiguator" value via the
82 //!   `-C metadata` commandline argument. This disambiguator is then fed into
83 //!   the symbol hash of every exported item. Consequently, the symbols in two
84 //!   identical crates but with different disambiguators are not in conflict
85 //!   with each other. This facility is mainly intended to be used by build
86 //!   tools like Cargo.
87 //!
88 //! A note on symbol name stability
89 //! -------------------------------
90 //! Previous versions of the compiler resorted to feeding NodeIds into the
91 //! symbol hash in order to disambiguate between items with the same path. The
92 //! current version of the name generation algorithm takes great care not to do
93 //! that, since NodeIds are notoriously unstable: A small change to the
94 //! code base will offset all NodeIds after the change and thus, much as using
95 //! the SVH in the hash, invalidate an unbounded number of symbol names. This
96 //! makes re-using previously compiled code for incremental compilation
97 //! virtually impossible. Thus, symbol hash generation exclusively relies on
98 //! DefPaths which are much more robust in the face of changes to the code base.
99
100 use trans::{CrateContext, Instance, gensym_name};
101 use util::sha2::{Digest, Sha256};
102
103 use rustc::middle::cstore;
104 use rustc::middle::def_id::DefId;
105 use rustc::middle::ty::{self, TypeFoldable};
106 use rustc::front::map::definitions::DefPath;
107
108 use std::fmt::Write;
109 use syntax::ast;
110 use syntax::parse::token;
111 use serialize::hex::ToHex;
112 use super::link;
113
114 pub fn def_id_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_id: DefId) -> String {
115
116     let def_path = tcx.def_path(def_id);
117     let mut s = String::with_capacity(def_path.len() * 16);
118
119     let def_path = if def_id.is_local() {
120         s.push_str(&tcx.crate_name[..]);
121         s.push_str("/");
122         s.push_str(&tcx.sess.crate_disambiguator.borrow()[..]);
123         &def_path[..]
124     } else {
125         s.push_str(&tcx.sess.cstore.crate_name(def_id.krate)[..]);
126         s.push_str("/");
127         s.push_str(&tcx.sess.cstore.crate_disambiguator(def_id.krate));
128         &def_path[1..]
129     };
130
131     for component in def_path {
132         write!(s,
133                "::{}[{}]",
134                component.data.as_interned_str(),
135                component.disambiguator)
136             .unwrap();
137     }
138
139     s
140 }
141
142 fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
143                              def_path: &DefPath,
144                              originating_crate: ast::CrateNum,
145                              parameters: &[ty::Ty<'tcx>])
146                              -> String {
147     let tcx = ccx.tcx();
148
149     let mut hash_state = ccx.symbol_hasher().borrow_mut();
150
151     hash_state.reset();
152
153     if originating_crate == cstore::LOCAL_CRATE {
154         hash_state.input_str(&tcx.sess.crate_disambiguator.borrow()[..]);
155     } else {
156         hash_state.input_str(&tcx.sess.cstore.crate_disambiguator(originating_crate));
157     }
158
159     for component in def_path {
160         let disambiguator_bytes = [(component.disambiguator >>  0) as u8,
161                                    (component.disambiguator >>  8) as u8,
162                                    (component.disambiguator >> 16) as u8,
163                                    (component.disambiguator >> 24) as u8];
164         hash_state.input(&disambiguator_bytes);
165     }
166
167     for t in parameters {
168        assert!(!t.has_erasable_regions());
169        assert!(!t.needs_subst());
170        let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string);
171        hash_state.input(&encoded_type[..]);
172     }
173
174     return format!("h{}", truncated_hash_result(&mut *hash_state));
175
176     fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String {
177         let output = symbol_hasher.result_bytes();
178         // 64 bits should be enough to avoid collisions.
179         output[.. 8].to_hex()
180     }
181 }
182
183 fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
184                                            instance: &Instance<'tcx>,
185                                            suffix: Option<&str>)
186                                            -> String {
187     let &Instance { def: mut def_id, params: parameters } = instance;
188
189     if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) {
190         if let Some(&src_def_id) = ccx.external_srcs().borrow().get(&node_id) {
191             def_id = src_def_id;
192         }
193     }
194
195     let def_path = ccx.tcx().def_path(def_id);
196     let hash = get_symbol_hash(ccx, &def_path, def_id.krate, parameters.as_slice());
197
198     let mut path = Vec::with_capacity(16);
199
200     if def_id.is_local() {
201         path.push(ccx.tcx().crate_name.clone());
202     }
203
204     path.extend(def_path.into_iter().map(|e| e.data.as_interned_str()));
205
206     if let Some(suffix) = suffix {
207         path.push(token::intern_and_get_ident(suffix));
208     }
209
210     link::mangle(path.into_iter(), Some(&hash[..]))
211 }
212
213 pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
214                                instance: &Instance<'tcx>)
215                                -> String {
216     exported_name_with_opt_suffix(ccx, instance, None)
217 }
218
219 pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
220                                            instance: &Instance<'tcx>,
221                                            suffix: &str)
222                                            -> String {
223    exported_name_with_opt_suffix(ccx, instance, Some(suffix))
224 }
225
226 /// Only symbols that are invisible outside their compilation unit should use a
227 /// name generated by this function.
228 pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
229                                                     t: ty::Ty<'tcx>,
230                                                     suffix: &str)
231                                                     -> String {
232     let path = [token::intern(&t.to_string()).as_str(),
233                 gensym_name(suffix).as_str()];
234     let hash = get_symbol_hash(ccx, &Vec::new(), cstore::LOCAL_CRATE, &[t]);
235     link::mangle(path.iter().cloned(), Some(&hash[..]))
236 }