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