1 // Copyright 2012 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 use back::link::exported_name;
12 use driver::session;
13 use lib::llvm::ValueRef;
14 use middle::trans::base::{set_llvm_fn_attrs, set_inline_hint};
15 use middle::trans::base::{trans_enum_variant, push_ctxt, get_item_val};
16 use middle::trans::base::{trans_fn, decl_internal_rust_fn};
17 use middle::trans::base;
18 use middle::trans::common::*;
19 use middle::trans::intrinsic;
20 use middle::ty;
21 use middle::typeck;
22 use util::ppaux::Repr;
23
24 use syntax::abi;
25 use syntax::ast;
26 use syntax::ast_map;
27 use syntax::ast_util::local_def;
28 use std::hash::{sip, Hash};
29
30 pub fn monomorphic_fn(ccx: &CrateContext,
31 fn_id: ast::DefId,
32 real_substs: &ty::substs,
33 vtables: Option<typeck::vtable_res>,
34 self_vtables: Option<typeck::vtable_param_res>,
35 ref_id: Option<ast::NodeId>)
36 -> (ValueRef, bool) {
37 debug!("monomorphic_fn(\
38 fn_id={}, \
39 real_substs={}, \
40 vtables={}, \
41 self_vtable={}, \
42 ref_id={:?})",
43 fn_id.repr(ccx.tcx()),
44 real_substs.repr(ccx.tcx()),
45 vtables.repr(ccx.tcx()),
46 self_vtables.repr(ccx.tcx()),
47 ref_id);
48
49 assert!(real_substs.tps.iter().all(|t| {
50 !ty::type_needs_infer(*t) && !ty::type_has_params(*t)
51 }));
52
53 let _icx = push_ctxt("monomorphic_fn");
54
55 let substs_iter = real_substs.self_ty.iter().chain(real_substs.tps.iter());
56 let param_ids: Vec<MonoParamId> = match vtables {
57 Some(ref vts) => {
58 debug!("make_mono_id vtables={} psubsts={}",
59 vts.repr(ccx.tcx()), real_substs.tps.repr(ccx.tcx()));
60 let vts_iter = self_vtables.iter().chain(vts.iter());
61 vts_iter.zip(substs_iter).map(|(vtable, subst)| MonoParamId {
62 subst: *subst,
63 // Do we really need the vtables to be hashed? Isn't the type enough?
64 vtables: vtable.iter().map(|vt| make_vtable_id(ccx, vt)).collect()
65 }).collect()
66 }
67 None => substs_iter.map(|subst| MonoParamId {
68 subst: *subst,
69 vtables: Vec::new()
70 }).collect()
71 };
72
73 let hash_id = MonoId {
74 def: fn_id,
75 params: param_ids
76 };
77
78 match ccx.monomorphized.borrow().find(&hash_id) {
79 Some(&val) => {
80 debug!("leaving monomorphic fn {}",
81 ty::item_path_str(ccx.tcx(), fn_id));
82 return (val, false);
83 }
84 None => ()
85 }
86
87 let psubsts = param_substs {
88 tys: real_substs.tps.clone(),
89 vtables: vtables,
90 self_ty: real_substs.self_ty.clone(),
91 self_vtables: self_vtables
92 };
93
94 debug!("monomorphic_fn(\
95 fn_id={}, \
96 psubsts={}, \
97 hash_id={:?})",
98 fn_id.repr(ccx.tcx()),
99 psubsts.repr(ccx.tcx()),
100 hash_id);
101
102 let tpt = ty::lookup_item_type(ccx.tcx(), fn_id);
103 let llitem_ty = tpt.ty;
104
105 // We need to do special handling of the substitutions if we are
106 // calling a static provided method. This is sort of unfortunate.
107 let mut is_static_provided = None;
108
109 let map_node = session::expect(
110 ccx.sess(),
111 ccx.tcx.map.find(fn_id.node),
112 || {
113 (format!("while monomorphizing {:?}, couldn't find it in the \
114 item map (may have attempted to monomorphize an item \
115 defined in a different crate?)", fn_id)).to_strbuf()
116 });
117
118 match map_node {
119 ast_map::NodeForeignItem(_) => {
120 if ccx.tcx.map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic {
121 // Foreign externs don't have to be monomorphized.
122 return (get_item_val(ccx, fn_id.node), true);
123 }
124 }
125 ast_map::NodeTraitMethod(method) => {
126 match *method {
127 ast::Provided(m) => {
128 // If this is a static provided method, indicate that
129 // and stash the number of params on the method.
130 if m.explicit_self.node == ast::SelfStatic {
131 is_static_provided = Some(m.generics.ty_params.len());
132 }
133 }
134 _ => {}
135 }
136 }
137 _ => {}
138 }
139
140 debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx()));
141 let mono_ty = match is_static_provided {
142 None => ty::subst_tps(ccx.tcx(), real_substs.tps.as_slice(),
143 real_substs.self_ty, llitem_ty),
144 Some(num_method_ty_params) => {
145 // Static default methods are a little unfortunate, in
146 // that the "internal" and "external" type of them differ.
147 // Internally, the method body can refer to Self, but the
148 // externally visible type of the method has a type param
149 // inserted in between the trait type params and the
150 // method type params. The substs that we are given are
151 // the proper substs *internally* to the method body, so
152 // we have to use those when compiling it.
153 //
154 // In order to get the proper substitution to use on the
155 // type of the method, we pull apart the substitution and
156 // stick a substitution for the self type in.
157 // This is a bit unfortunate.
158
159 let idx = real_substs.tps.len() - num_method_ty_params;
160 let substs = Vec::from_slice(real_substs.tps.slice(0, idx))
161 .append([real_substs.self_ty.unwrap()])
162 .append(real_substs.tps.tailn(idx));
163 debug!("static default: changed substitution to {}",
164 substs.repr(ccx.tcx()));
165
166 ty::subst_tps(ccx.tcx(), substs.as_slice(), None, llitem_ty)
167 }
168 };
169
170 let f = match ty::get(mono_ty).sty {
171 ty::ty_bare_fn(ref f) => {
172 assert!(f.abi == abi::Rust || f.abi == abi::RustIntrinsic);
173 f
174 }
175 _ => fail!("expected bare rust fn or an intrinsic")
176 };
177
178 ccx.stats.n_monos.set(ccx.stats.n_monos.get() + 1);
179
180 let depth;
181 {
182 let mut monomorphizing = ccx.monomorphizing.borrow_mut();
183 depth = match monomorphizing.find(&fn_id) {
184 Some(&d) => d, None => 0
185 };
186
187 // Random cut-off -- code that needs to instantiate the same function
188 // recursively more than thirty times can probably safely be assumed
189 // to be causing an infinite expansion.
190 if depth > ccx.sess().recursion_limit.get() {
191 ccx.sess().span_fatal(ccx.tcx.map.span(fn_id.node),
192 "reached the recursion limit during monomorphization");
193 }
194
195 monomorphizing.insert(fn_id, depth + 1);
196 }
197
198 let s = ccx.tcx.map.with_path(fn_id.node, |path| {
199 let mut state = sip::SipState::new();
200 hash_id.hash(&mut state);
201 mono_ty.hash(&mut state);
202
203 exported_name(path, format!("h{}", state.result()),
204 ccx.link_meta.crateid.version_or_default())
205 });
206 debug!("monomorphize_fn mangled to {}", s);
207
208 // This shouldn't need to option dance.
209 let mut hash_id = Some(hash_id);
210 let mk_lldecl = || {
211 let lldecl = decl_internal_rust_fn(ccx, false,
212 f.sig.inputs.as_slice(),
213 f.sig.output, s);
214 ccx.monomorphized.borrow_mut().insert(hash_id.take_unwrap(), lldecl);
215 lldecl
216 };
217
218 let lldecl = match map_node {
219 ast_map::NodeItem(i) => {
220 match *i {
221 ast::Item {
222 node: ast::ItemFn(decl, _, _, _, body),
223 ..
224 } => {
225 let d = mk_lldecl();
226 set_llvm_fn_attrs(i.attrs.as_slice(), d);
227 trans_fn(ccx, decl, body, d, Some(&psubsts), fn_id.node, []);
228 d
229 }
230 _ => {
231 ccx.sess().bug("Can't monomorphize this kind of item")
232 }
233 }
234 }
235 ast_map::NodeForeignItem(i) => {
236 let simple = intrinsic::get_simple_intrinsic(ccx, i);
237 match simple {
238 Some(decl) => decl,
239 None => {
240 let d = mk_lldecl();
241 intrinsic::trans_intrinsic(ccx, d, i, &psubsts, ref_id);
242 d
243 }
244 }
245 }
246 ast_map::NodeVariant(v) => {
247 let parent = ccx.tcx.map.get_parent(fn_id.node);
248 let tvs = ty::enum_variants(ccx.tcx(), local_def(parent));
249 let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap();
250 let d = mk_lldecl();
251 set_inline_hint(d);
252 match v.node.kind {
253 ast::TupleVariantKind(ref args) => {
254 trans_enum_variant(ccx,
255 parent,
256 v,
257 args.as_slice(),
258 this_tv.disr_val,
259 Some(&psubsts),
260 d);
261 }
262 ast::StructVariantKind(_) =>
263 ccx.sess().bug("can't monomorphize struct variants"),
264 }
265 d
266 }
267 ast_map::NodeMethod(mth) => {
268 let d = mk_lldecl();
269 set_llvm_fn_attrs(mth.attrs.as_slice(), d);
270 trans_fn(ccx, mth.decl, mth.body, d, Some(&psubsts), mth.id, []);
271 d
272 }
273 ast_map::NodeTraitMethod(method) => {
274 match *method {
275 ast::Provided(mth) => {
276 let d = mk_lldecl();
277 set_llvm_fn_attrs(mth.attrs.as_slice(), d);
278 trans_fn(ccx, mth.decl, mth.body, d, Some(&psubsts), mth.id, []);
279 d
280 }
281 _ => {
282 ccx.sess().bug(format!("can't monomorphize a {:?}",
283 map_node))
284 }
285 }
286 }
287 ast_map::NodeStructCtor(struct_def) => {
288 let d = mk_lldecl();
289 set_inline_hint(d);
290 base::trans_tuple_struct(ccx,
291 struct_def.fields.as_slice(),
292 struct_def.ctor_id.expect("ast-mapped tuple struct \
293 didn't have a ctor id"),
294 Some(&psubsts),
295 d);
296 d
297 }
298
299 // Ugh -- but this ensures any new variants won't be forgotten
300 ast_map::NodeLifetime(..) |
301 ast_map::NodeExpr(..) |
302 ast_map::NodeStmt(..) |
303 ast_map::NodeArg(..) |
304 ast_map::NodeBlock(..) |
305 ast_map::NodeLocal(..) => {
306 ccx.sess().bug(format!("can't monomorphize a {:?}", map_node))
307 }
308 };
309
310 ccx.monomorphizing.borrow_mut().insert(fn_id, depth);
311
312 debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id));
313 (lldecl, false)
314 }
315
316 // Used to identify cached monomorphized functions and vtables
317 #[deriving(Eq, TotalEq, Hash)]
318 pub struct MonoParamId {
319 pub subst: ty::t,
320 // Do we really need the vtables to be hashed? Isn't the type enough?
321 pub vtables: Vec<MonoId>
322 }
323
324 #[deriving(Eq, TotalEq, Hash)]
325 pub struct MonoId {
326 pub def: ast::DefId,
327 pub params: Vec<MonoParamId>
328 }
329
330 pub fn make_vtable_id(ccx: &CrateContext,
331 origin: &typeck::vtable_origin)
332 -> MonoId {
333 match origin {
334 &typeck::vtable_static(impl_id, ref substs, ref sub_vtables) => {
335 MonoId {
336 def: impl_id,
337 params: sub_vtables.iter().zip(substs.iter()).map(|(vtable, subst)| {
338 MonoParamId {
339 subst: *subst,
340 // Do we really need the vtables to be hashed? Isn't the type enough?
341 vtables: vtable.iter().map(|vt| make_vtable_id(ccx, vt)).collect()
342 }
343 }).collect()
344 }
345 }
346
347 // can't this be checked at the callee?
348 _ => fail!("make_vtable_id needs vtable_static")
349 }
350 }
librustc/middle/trans/monomorphize.rs:317:31-317:31 -struct- definition:
pub struct MonoParamId {
pub subst: ty::t,
// Do we really need the vtables to be hashed? Isn't the type enough?
references:- 1666: }
67: None => substs_iter.map(|subst| MonoParamId {
68: subst: *subst,
--
337: params: sub_vtables.iter().zip(substs.iter()).map(|(vtable, subst)| {
338: MonoParamId {
339: subst: *subst,
librustc/middle/trans/monomorphize.rs:29:1-29:1 -fn- definition:
pub fn monomorphic_fn(ccx: &CrateContext,
fn_id: ast::DefId,
real_substs: &ty::substs,
references:- 2librustc/middle/trans/callee.rs:
389: let (val, must_cast) =
390: monomorphize::monomorphic_fn(ccx, def_id, &substs,
391: vtables, self_vtables,
librustc/middle/trans/base.rs:
497: let vtables = typeck::check::vtable::trans_resolve_method(ccx.tcx(), did.node, &tsubsts);
498: let (val, _) = monomorphize::monomorphic_fn(ccx, did, &tsubsts, vtables, None, None);
librustc/middle/trans/monomorphize.rs:329:1-329:1 -fn- definition:
pub fn make_vtable_id(ccx: &CrateContext,
origin: &typeck::vtable_origin)
-> MonoId {
references:- 3340: // Do we really need the vtables to be hashed? Isn't the type enough?
341: vtables: vtable.iter().map(|vt| make_vtable_id(ccx, vt)).collect()
342: }
librustc/middle/trans/meth.rs:
439: // Check the cache.
440: let hash_id = (self_ty, monomorphize::make_vtable_id(ccx, origins.get(0)));
441: match ccx.vtables.borrow().find(&hash_id) {
librustc/middle/trans/monomorphize.rs:
63: // Do we really need the vtables to be hashed? Isn't the type enough?
64: vtables: vtable.iter().map(|vt| make_vtable_id(ccx, vt)).collect()
65: }).collect()
librustc/middle/trans/monomorphize.rs:324:31-324:31 -struct- definition:
pub struct MonoId {
pub def: ast::DefId,
pub params: Vec<MonoParamId>
references:- 17334: &typeck::vtable_static(impl_id, ref substs, ref sub_vtables) => {
335: MonoId {
336: def: impl_id,
librustc/middle/trans/context.rs:
82: /// Cache generated vtables
83: pub vtables: RefCell<HashMap<(ty::t, MonoId), ValueRef>>,
84: /// Cache of constant strings,
librustc/middle/trans/monomorphize.rs:
331: origin: &typeck::vtable_origin)
332: -> MonoId {
333: match origin {