(index<- )        ./librustc/middle/trans/monomorphize.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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_idast::DefId,
  32                        real_substs: &ty::substs,
  33                        vtablesOption<typeck::vtable_res>,
  34                        self_vtablesOption<typeck::vtable_param_res>,
  35                        ref_idOption<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_idsVec<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:- 16
66:         }
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:- 2
librustc/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:- 3
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:                     }
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:- 17
334:         &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 {