]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/context.rs
652336ecc000b4c889ebb767a8e2cba9d048c61d
[rust.git] / src / librustc / middle / trans / context.rs
1 // Copyright 2013 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
12 use driver::session;
13 use driver::session::NoDebugInfo;
14 use lib::llvm::{ContextRef, ModuleRef, ValueRef};
15 use lib::llvm::{llvm, TargetData, TypeNames};
16 use lib::llvm::mk_target_data;
17 use metadata::common::LinkMeta;
18 use middle::astencode;
19 use middle::resolve;
20 use middle::trans::adt;
21 use middle::trans::base;
22 use middle::trans::builder::Builder;
23 use middle::trans::common::{C_i32, C_null};
24 use middle::trans::common::{mono_id,ExternMap,tydesc_info,BuilderRef_res,Stats};
25 use middle::trans::base::{decl_crate_map};
26 use middle::trans::debuginfo;
27 use middle::trans::type_::Type;
28 use middle::ty;
29 use util::sha2::Sha256;
30 use util::nodemap::{NodeMap, NodeSet, DefIdMap};
31
32 use std::cell::{Cell, RefCell};
33 use std::c_str::ToCStr;
34 use std::local_data;
35 use std::libc::c_uint;
36 use collections::{HashMap, HashSet};
37 use syntax::ast;
38 use syntax::parse::token::InternedString;
39
40 pub struct CrateContext {
41     sess: session::Session,
42     llmod: ModuleRef,
43     llcx: ContextRef,
44     metadata_llmod: ModuleRef,
45     td: TargetData,
46     tn: TypeNames,
47     externs: RefCell<ExternMap>,
48     intrinsics: HashMap<&'static str, ValueRef>,
49     item_vals: RefCell<NodeMap<ValueRef>>,
50     exp_map2: resolve::ExportMap2,
51     reachable: @RefCell<NodeSet>,
52     item_symbols: RefCell<NodeMap<~str>>,
53     link_meta: LinkMeta,
54     drop_glues: RefCell<HashMap<ty::t, ValueRef>>,
55     tydescs: RefCell<HashMap<ty::t, @tydesc_info>>,
56     // Set when running emit_tydescs to enforce that no more tydescs are
57     // created.
58     finished_tydescs: Cell<bool>,
59     // Track mapping of external ids to local items imported for inlining
60     external: RefCell<DefIdMap<Option<ast::NodeId>>>,
61     // Backwards version of the `external` map (inlined items to where they
62     // came from)
63     external_srcs: RefCell<NodeMap<ast::DefId>>,
64     // A set of static items which cannot be inlined into other crates. This
65     // will pevent in IIItem() structures from being encoded into the metadata
66     // that is generated
67     non_inlineable_statics: RefCell<NodeSet>,
68     // Cache instances of monomorphized functions
69     monomorphized: RefCell<HashMap<mono_id, ValueRef>>,
70     monomorphizing: RefCell<DefIdMap<uint>>,
71     // Cache generated vtables
72     vtables: RefCell<HashMap<(ty::t, mono_id), ValueRef>>,
73     // Cache of constant strings,
74     const_cstr_cache: RefCell<HashMap<InternedString, ValueRef>>,
75
76     // Reverse-direction for const ptrs cast from globals.
77     // Key is an int, cast from a ValueRef holding a *T,
78     // Val is a ValueRef holding a *[T].
79     //
80     // Needed because LLVM loses pointer->pointee association
81     // when we ptrcast, and we have to ptrcast during translation
82     // of a [T] const because we form a slice, a [*T,int] pair, not
83     // a pointer to an LLVM array type.
84     const_globals: RefCell<HashMap<int, ValueRef>>,
85
86     // Cache of emitted const values
87     const_values: RefCell<NodeMap<ValueRef>>,
88
89     // Cache of external const values
90     extern_const_values: RefCell<DefIdMap<ValueRef>>,
91
92     impl_method_cache: RefCell<HashMap<(ast::DefId, ast::Name), ast::DefId>>,
93
94     // Cache of closure wrappers for bare fn's.
95     closure_bare_wrapper_cache: RefCell<HashMap<ValueRef, ValueRef>>,
96
97     module_data: RefCell<HashMap<~str, ValueRef>>,
98     lltypes: RefCell<HashMap<ty::t, Type>>,
99     llsizingtypes: RefCell<HashMap<ty::t, Type>>,
100     adt_reprs: RefCell<HashMap<ty::t, @adt::Repr>>,
101     symbol_hasher: RefCell<Sha256>,
102     type_hashcodes: RefCell<HashMap<ty::t, ~str>>,
103     all_llvm_symbols: RefCell<HashSet<~str>>,
104     tcx: ty::ctxt,
105     maps: astencode::Maps,
106     stats: @Stats,
107     tydesc_type: Type,
108     int_type: Type,
109     opaque_vec_type: Type,
110     builder: BuilderRef_res,
111     crate_map: ValueRef,
112     crate_map_name: ~str,
113     // Set when at least one function uses GC. Needed so that
114     // decl_gc_metadata knows whether to link to the module metadata, which
115     // is not emitted by LLVM's GC pass when no functions use GC.
116     uses_gc: bool,
117     dbg_cx: Option<debuginfo::CrateDebugContext>,
118     do_not_commit_warning_issued: Cell<bool>,
119 }
120
121 impl CrateContext {
122     pub fn new(sess: session::Session,
123                name: &str,
124                tcx: ty::ctxt,
125                emap2: resolve::ExportMap2,
126                maps: astencode::Maps,
127                symbol_hasher: Sha256,
128                link_meta: LinkMeta,
129                reachable: @RefCell<NodeSet>)
130                -> CrateContext {
131         unsafe {
132             let llcx = llvm::LLVMContextCreate();
133             set_task_llcx(llcx);
134             let llmod = name.with_c_str(|buf| {
135                 llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
136             });
137             let metadata_llmod = format!("{}_metadata", name).with_c_str(|buf| {
138                 llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
139             });
140             let data_layout: &str = sess.targ_cfg.target_strs.data_layout;
141             let targ_triple: &str = sess.targ_cfg.target_strs.target_triple;
142             data_layout.with_c_str(|buf| {
143                 llvm::LLVMSetDataLayout(llmod, buf);
144                 llvm::LLVMSetDataLayout(metadata_llmod, buf);
145             });
146             targ_triple.with_c_str(|buf| {
147                 llvm::LLVMRustSetNormalizedTarget(llmod, buf);
148                 llvm::LLVMRustSetNormalizedTarget(metadata_llmod, buf);
149             });
150             let targ_cfg = sess.targ_cfg;
151
152             let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
153             let tn = TypeNames::new();
154
155             let mut intrinsics = base::declare_intrinsics(llmod);
156             if sess.opts.debuginfo != NoDebugInfo {
157                 base::declare_dbg_intrinsics(llmod, &mut intrinsics);
158             }
159             let int_type = Type::int(targ_cfg.arch);
160             let tydesc_type = Type::tydesc(targ_cfg.arch);
161             let opaque_vec_type = Type::opaque_vec(targ_cfg.arch);
162
163             let mut str_slice_ty = Type::named_struct("str_slice");
164             str_slice_ty.set_struct_body([Type::i8p(), int_type], false);
165
166             tn.associate_type("tydesc", &tydesc_type);
167             tn.associate_type("str_slice", &str_slice_ty);
168
169             let (crate_map_name, crate_map) = decl_crate_map(sess, link_meta.clone(), llmod);
170             let dbg_cx = if sess.opts.debuginfo != NoDebugInfo {
171                 Some(debuginfo::CrateDebugContext::new(llmod))
172             } else {
173                 None
174             };
175
176             if sess.count_llvm_insns() {
177                 base::init_insn_ctxt()
178             }
179
180             CrateContext {
181                  sess: sess,
182                  llmod: llmod,
183                  llcx: llcx,
184                  metadata_llmod: metadata_llmod,
185                  td: td,
186                  tn: tn,
187                  externs: RefCell::new(HashMap::new()),
188                  intrinsics: intrinsics,
189                  item_vals: RefCell::new(NodeMap::new()),
190                  exp_map2: emap2,
191                  reachable: reachable,
192                  item_symbols: RefCell::new(NodeMap::new()),
193                  link_meta: link_meta,
194                  drop_glues: RefCell::new(HashMap::new()),
195                  tydescs: RefCell::new(HashMap::new()),
196                  finished_tydescs: Cell::new(false),
197                  external: RefCell::new(DefIdMap::new()),
198                  external_srcs: RefCell::new(NodeMap::new()),
199                  non_inlineable_statics: RefCell::new(NodeSet::new()),
200                  monomorphized: RefCell::new(HashMap::new()),
201                  monomorphizing: RefCell::new(DefIdMap::new()),
202                  vtables: RefCell::new(HashMap::new()),
203                  const_cstr_cache: RefCell::new(HashMap::new()),
204                  const_globals: RefCell::new(HashMap::new()),
205                  const_values: RefCell::new(NodeMap::new()),
206                  extern_const_values: RefCell::new(DefIdMap::new()),
207                  impl_method_cache: RefCell::new(HashMap::new()),
208                  closure_bare_wrapper_cache: RefCell::new(HashMap::new()),
209                  module_data: RefCell::new(HashMap::new()),
210                  lltypes: RefCell::new(HashMap::new()),
211                  llsizingtypes: RefCell::new(HashMap::new()),
212                  adt_reprs: RefCell::new(HashMap::new()),
213                  symbol_hasher: RefCell::new(symbol_hasher),
214                  type_hashcodes: RefCell::new(HashMap::new()),
215                  all_llvm_symbols: RefCell::new(HashSet::new()),
216                  tcx: tcx,
217                  maps: maps,
218                  stats: @Stats {
219                    n_static_tydescs: Cell::new(0u),
220                    n_glues_created: Cell::new(0u),
221                    n_null_glues: Cell::new(0u),
222                    n_real_glues: Cell::new(0u),
223                    n_fns: Cell::new(0u),
224                    n_monos: Cell::new(0u),
225                    n_inlines: Cell::new(0u),
226                    n_closures: Cell::new(0u),
227                    n_llvm_insns: Cell::new(0u),
228                    llvm_insns: RefCell::new(HashMap::new()),
229                    fn_stats: RefCell::new(~[]),
230                  },
231                  tydesc_type: tydesc_type,
232                  int_type: int_type,
233                  opaque_vec_type: opaque_vec_type,
234                  builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
235                  crate_map: crate_map,
236                  crate_map_name: crate_map_name,
237                  uses_gc: false,
238                  dbg_cx: dbg_cx,
239                  do_not_commit_warning_issued: Cell::new(false),
240             }
241         }
242     }
243
244     pub fn builder<'a>(&'a self) -> Builder<'a> {
245         Builder::new(self)
246     }
247
248     pub fn const_inbounds_gepi(&self,
249                                pointer: ValueRef,
250                                indices: &[uint]) -> ValueRef {
251         debug!("const_inbounds_gepi: pointer={} indices={:?}",
252                self.tn.val_to_str(pointer), indices);
253         let v: ~[ValueRef] =
254             indices.iter().map(|i| C_i32(*i as i32)).collect();
255         unsafe {
256             llvm::LLVMConstInBoundsGEP(pointer,
257                                        v.as_ptr(),
258                                        indices.len() as c_uint)
259         }
260     }
261
262     pub fn offsetof_gep(&self,
263                         llptr_ty: Type,
264                         indices: &[uint]) -> ValueRef {
265         /*!
266          * Returns the offset of applying the given GEP indices
267          * to an instance of `llptr_ty`. Similar to `offsetof` in C,
268          * except that `llptr_ty` must be a pointer type.
269          */
270
271         unsafe {
272             let null = C_null(llptr_ty);
273             llvm::LLVMConstPtrToInt(self.const_inbounds_gepi(null, indices),
274                                     self.int_type.to_ref())
275         }
276     }
277 }
278
279 #[unsafe_destructor]
280 impl Drop for CrateContext {
281     fn drop(&mut self) {
282         unset_task_llcx();
283     }
284 }
285
286 local_data_key!(task_local_llcx_key: @ContextRef)
287
288 pub fn task_llcx() -> ContextRef {
289     let opt = local_data::get(task_local_llcx_key, |k| k.map(|k| *k));
290     *opt.expect("task-local LLVMContextRef wasn't ever set!")
291 }
292
293 fn set_task_llcx(c: ContextRef) {
294     local_data::set(task_local_llcx_key, @c);
295 }
296
297 fn unset_task_llcx() {
298     local_data::pop(task_local_llcx_key);
299 }