(index<- )        ./librustc/middle/trans/reflect.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::mangle_internal_name_by_path_and_seq;
  12  use lib::llvm::{ValueRef, llvm};
  13  use middle::trans::adt;
  14  use middle::trans::base::*;
  15  use middle::trans::build::*;
  16  use middle::trans::callee::ArgVals;
  17  use middle::trans::callee;
  18  use middle::trans::common::*;
  19  use middle::trans::datum::*;
  20  use middle::trans::glue;
  21  use middle::trans::machine;
  22  use middle::trans::meth;
  23  use middle::trans::type_::Type;
  24  use middle::trans::type_of::*;
  25  use middle::ty;
  26  use util::ppaux::ty_to_str;
  27  
  28  use std::rc::Rc;
  29  use arena::TypedArena;
  30  use libc::c_uint;
  31  use syntax::ast::DefId;
  32  use syntax::ast;
  33  use syntax::ast_map;
  34  use syntax::parse::token::{InternedString, special_idents};
  35  use syntax::parse::token;
  36  
  37  pub struct Reflector<'a, 'b> {
  38      visitor_val: ValueRef,
  39      visitor_methods: &'a [Rc<ty::Method>],
  40      final_bcx: &'b Block<'b>,
  41      tydesc_ty: Type,
  42      bcx: &'b Block<'b>
  43  }
  44  
  45  impl<'a, 'b> Reflector<'a, 'b> {
  46      pub fn c_uint(&mut self, uuint) -> ValueRef {
  47          C_uint(self.bcx.ccx(), u)
  48      }
  49  
  50      pub fn c_bool(&mut self, bbool) -> ValueRef {
  51          C_bool(self.bcx.ccx(), b)
  52      }
  53  
  54      pub fn c_slice(&mut self, sInternedString) -> ValueRef {
  55          // We're careful to not use first class aggregates here because that
  56          // will kick us off fast isel. (Issue #4352.)
  57          let bcx = self.bcx;
  58          let str_ty = ty::mk_str_slice(bcx.tcx(), ty::ReStatic, ast::MutImmutable);
  59          let scratch = rvalue_scratch_datum(bcx, str_ty, "");
  60          let len = C_uint(bcx.ccx(), s.get().len());
  61          let c_str = PointerCast(bcx, C_cstr(bcx.ccx(), s, false), Type::i8p(bcx.ccx()));
  62          Store(bcx, c_str, GEPi(bcx, scratch.val, [ 0, 0 ]));
  63          Store(bcx, len, GEPi(bcx, scratch.val, [ 0, 1 ]));
  64          scratch.val
  65      }
  66  
  67      pub fn c_size_and_align(&mut self, tty::t) -> Vec<ValueRef> {
  68          let tr = type_of(self.bcx.ccx(), t);
  69          let s = machine::llsize_of_real(self.bcx.ccx(), tr);
  70          let a = machine::llalign_of_min(self.bcx.ccx(), tr);
  71          return vec!(self.c_uint(s as uint),
  72               self.c_uint(a as uint));
  73      }
  74  
  75      pub fn c_tydesc(&mut self, tty::t) -> ValueRef {
  76          let bcx = self.bcx;
  77          let static_ti = get_tydesc(bcx.ccx(), t);
  78          glue::lazily_emit_visit_glue(bcx.ccx(), &*static_ti);
  79          PointerCast(bcx, static_ti.tydesc, self.tydesc_ty.ptr_to())
  80      }
  81  
  82      pub fn c_mt(&mut self, mt&ty::mt) -> Vec<ValueRef> {
  83          vec!(self.c_uint(mt.mutbl as uint),
  84            self.c_tydesc(mt.ty))
  85      }
  86  
  87      pub fn visit(&mut self, ty_name&str, args&[ValueRef]) {
  88          let fcx = self.bcx.fcx;
  89          let tcx = self.bcx.tcx();
  90          let mth_idx = ty::method_idx(token::str_to_ident("visit_".to_owned() + ty_name),
  91                                       self.visitor_methods.as_slice()).expect(
  92                  format!("couldn't find visit method for {}", ty_name));
  93          let mth_ty =
  94              ty::mk_bare_fn(tcx,
  95                             self.visitor_methods[mth_idx].fty.clone());
  96          let v = self.visitor_val;
  97          debug!("passing {} args:", args.len());
  98          let mut bcx = self.bcx;
  99          for (i, a) in args.iter().enumerate() {
 100              debug!("arg {}{}", i, bcx.val_to_str(*a));
 101          }
 102          let result = unpack_result!(bcx, callee::trans_call_inner(
 103              self.bcx, None, mth_ty,
 104              |bcx, _| meth::trans_trait_callee_from_llval(bcx,
 105                                                           mth_ty,
 106                                                           mth_idx,
 107                                                           v),
 108              ArgVals(args), None));
 109          let result = bool_to_i1(bcx, result);
 110          let next_bcx = fcx.new_temp_block("next");
 111          CondBr(bcx, result, next_bcx.llbb, self.final_bcx.llbb);
 112          self.bcx = next_bcx
 113      }
 114  
 115      pub fn bracketed(&mut self,
 116                       bracket_name&str,
 117                       extra&[ValueRef],
 118                       inner|&mut Reflector|) {
 119          self.visit("enter_" + bracket_name, extra);
 120          inner(self);
 121          self.visit("leave_" + bracket_name, extra);
 122      }
 123  
 124      pub fn leaf(&mut self, name&str) {
 125          self.visit(name, []);
 126      }
 127  
 128      // Entrypoint
 129      pub fn visit_ty(&mut self, tty::t) {
 130          let bcx = self.bcx;
 131          let tcx = bcx.tcx();
 132          debug!("reflect::visit_ty {}", ty_to_str(bcx.tcx(), t));
 133  
 134          match ty::get(t).sty {
 135            ty::ty_bot => self.leaf("bot"),
 136            ty::ty_nil => self.leaf("nil"),
 137            ty::ty_bool => self.leaf("bool"),
 138            ty::ty_char => self.leaf("char"),
 139            ty::ty_int(ast::TyI) => self.leaf("int"),
 140            ty::ty_int(ast::TyI8) => self.leaf("i8"),
 141            ty::ty_int(ast::TyI16) => self.leaf("i16"),
 142            ty::ty_int(ast::TyI32) => self.leaf("i32"),
 143            ty::ty_int(ast::TyI64) => self.leaf("i64"),
 144            ty::ty_uint(ast::TyU) => self.leaf("uint"),
 145            ty::ty_uint(ast::TyU8) => self.leaf("u8"),
 146            ty::ty_uint(ast::TyU16) => self.leaf("u16"),
 147            ty::ty_uint(ast::TyU32) => self.leaf("u32"),
 148            ty::ty_uint(ast::TyU64) => self.leaf("u64"),
 149            ty::ty_float(ast::TyF32) => self.leaf("f32"),
 150            ty::ty_float(ast::TyF64) => self.leaf("f64"),
 151            ty::ty_float(ast::TyF128) => self.leaf("f128"),
 152  
 153            // Should rename to vec_*.
 154            ty::ty_vec(ref mt, Some(sz)) => {
 155                let extra = (vec!(self.c_uint(sz))).append(self.c_size_and_align(t).as_slice());
 156                let extra = extra.append(self.c_mt(mt).as_slice());
 157                self.visit("evec_fixed".to_owned(), extra.as_slice())
 158            }
 159            ty::ty_vec(..) | ty::ty_str => fail!("unexpected unsized type"),
 160            // Should remove mt from box and uniq.
 161            ty::ty_box(typ) => {
 162                let extra = self.c_mt(&ty::mt {
 163                    ty: typ,
 164                    mutbl: ast::MutImmutable,
 165                });
 166                self.visit("box", extra.as_slice())
 167            }
 168            ty::ty_uniq(typ) => {
 169                match ty::get(typ).sty {
 170                    ty::ty_vec(ref mt, None) => {
 171                        let extra = Vec::new();
 172                        let extra = extra.append(self.c_mt(mt).as_slice());
 173                        self.visit("evec_uniq".to_owned(), extra.as_slice())
 174                    }
 175                    ty::ty_str => self.visit("estr_uniq".to_owned(), &[]),
 176                    _ => {
 177                        let extra = self.c_mt(&ty::mt {
 178                            ty: typ,
 179                            mutbl: ast::MutImmutable,
 180                        });
 181                        self.visit("uniq", extra.as_slice())
 182                    }
 183                }
 184            }
 185            ty::ty_ptr(ref mt) => {
 186                let extra = self.c_mt(mt);
 187                self.visit("ptr", extra.as_slice())
 188            }
 189            ty::ty_rptr(_, ref mt) => {
 190                match ty::get(mt.ty).sty {
 191                    ty::ty_vec(ref mt, None) => {
 192                        let (name, extra) = ("slice".to_owned(), Vec::new());
 193                        let extra = extra.append(self.c_mt(mt).as_slice());
 194                        self.visit("evec_".to_owned() + name, extra.as_slice())
 195                    }
 196                    ty::ty_str => self.visit("estr_slice".to_owned(), &[]),
 197                    _ => {
 198                        let extra = self.c_mt(mt);
 199                        self.visit("rptr", extra.as_slice())
 200                    }
 201                }
 202            }
 203  
 204            ty::ty_tup(ref tys) => {
 205                let extra = (vec!(self.c_uint(tys.len())))
 206                            .append(self.c_size_and_align(t).as_slice());
 207                self.bracketed("tup", extra.as_slice(), |this| {
 208                    for (i, t) in tys.iter().enumerate() {
 209                        let extra = vec!(this.c_uint(i), this.c_tydesc(*t));
 210                        this.visit("tup_field", extra.as_slice());
 211                    }
 212                })
 213            }
 214  
 215            // FIXME (#2594): fetch constants out of intrinsic
 216            // FIXME (#4809): visitor should break out bare fns from other fns
 217            ty::ty_closure(ref fty) => {
 218              let pureval = ast_fn_style_constant(fty.fn_style);
 219              let sigilval = match fty.store {
 220                  ty::UniqTraitStore => 2u,
 221                  ty::RegionTraitStore(..) => 4u,
 222              };
 223              let retval = if ty::type_is_bot(fty.sig.output) {0u} else {1u};
 224              let extra = vec!(self.c_uint(pureval),
 225                            self.c_uint(sigilval),
 226                            self.c_uint(fty.sig.inputs.len()),
 227                            self.c_uint(retval));
 228              self.visit("enter_fn", extra.as_slice());
 229              self.visit_sig(retval, &fty.sig);
 230              self.visit("leave_fn", extra.as_slice());
 231            }
 232  
 233            // FIXME (#2594): fetch constants out of intrinsic:: for the
 234            // numbers.
 235            ty::ty_bare_fn(ref fty) => {
 236              let pureval = ast_fn_style_constant(fty.fn_style);
 237              let sigilval = 0u;
 238              let retval = if ty::type_is_bot(fty.sig.output) {0u} else {1u};
 239              let extra = vec!(self.c_uint(pureval),
 240                            self.c_uint(sigilval),
 241                            self.c_uint(fty.sig.inputs.len()),
 242                            self.c_uint(retval));
 243              self.visit("enter_fn", extra.as_slice());
 244              self.visit_sig(retval, &fty.sig);
 245              self.visit("leave_fn", extra.as_slice());
 246            }
 247  
 248            ty::ty_struct(did, ref substs) => {
 249                let fields = ty::struct_fields(tcx, did, substs);
 250                let mut named_fields = false;
 251                if !fields.is_empty() {
 252                    named_fields = fields.get(0).ident.name !=
 253                        special_idents::unnamed_field.name;
 254                }
 255  
 256                let extra = (vec!(
 257                    self.c_slice(token::intern_and_get_ident(ty_to_str(tcx,
 258                                                                       t))),
 259                    self.c_bool(named_fields),
 260                    self.c_uint(fields.len())
 261                )).append(self.c_size_and_align(t).as_slice());
 262                self.bracketed("class", extra.as_slice(), |this| {
 263                    for (i, field) in fields.iter().enumerate() {
 264                        let extra = (vec!(
 265                          this.c_uint(i),
 266                          this.c_slice(token::get_ident(field.ident)),
 267                          this.c_bool(named_fields)
 268                        )).append(this.c_mt(&field.mt).as_slice());
 269                        this.visit("class_field", extra.as_slice());
 270                    }
 271                })
 272            }
 273  
 274            // FIXME (#2595): visiting all the variants in turn is probably
 275            // not ideal. It'll work but will get costly on big enums. Maybe
 276            // let the visitor tell us if it wants to visit only a particular
 277            // variant?
 278            ty::ty_enum(did, ref substs) => {
 279              let ccx = bcx.ccx();
 280              let repr = adt::represent_type(bcx.ccx(), t);
 281              let variants = ty::substd_enum_variants(ccx.tcx(), did, substs);
 282              let llptrty = type_of(ccx, t).ptr_to();
 283              let opaquety = ty::get_opaque_ty(ccx.tcx()).unwrap();
 284              let opaqueptrty = ty::mk_ptr(ccx.tcx(), ty::mt { ty: opaquety,
 285                                                             mutbl: ast::MutImmutable });
 286  
 287              let make_get_disr = || {
 288                  let sym = mangle_internal_name_by_path_and_seq(
 289                      ast_map::Values([].iter()).chain(None), "get_disr");
 290  
 291                  let llfdecl = decl_internal_rust_fn(ccx, false, [opaqueptrty], ty::mk_u64(), sym);
 292                  let arena = TypedArena::new();
 293                  let fcx = new_fn_ctxt(ccx, llfdecl, -1, false,
 294                                        ty::mk_u64(), None, None, &arena);
 295                  init_function(&fcx, false, ty::mk_u64());
 296  
 297                  let arg = unsafe {
 298                      //
 299                      // we know the return type of llfdecl is an int here, so
 300                      // no need for a special check to see if the return type
 301                      // is immediate.
 302                      //
 303                      llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
 304                  };
 305                  let bcx = fcx.entry_bcx.borrow().clone().unwrap();
 306                  let arg = BitCast(bcx, arg, llptrty);
 307                  let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
 308                  Store(bcx, ret, fcx.llretptr.get().unwrap());
 309                  match fcx.llreturn.get() {
 310                      Some(llreturn) => Br(bcx, llreturn),
 311                      None => {}
 312                  };
 313                  finish_fn(&fcx, bcx);
 314                  llfdecl
 315              };
 316  
 317              let enum_args = (vec!(self.c_uint(variants.len()), make_get_disr()))
 318                              .append(self.c_size_and_align(t).as_slice());
 319              self.bracketed("enum", enum_args.as_slice(), |this| {
 320                  for (i, v) in variants.iter().enumerate() {
 321                      let name = token::get_ident(v.name);
 322                      let variant_args = [this.c_uint(i),
 323                                           C_u64(ccx, v.disr_val),
 324                                           this.c_uint(v.args.len()),
 325                                           this.c_slice(name)];
 326                      this.bracketed("enum_variant",
 327                                     variant_args,
 328                                     |this| {
 329                          for (j, a) in v.args.iter().enumerate() {
 330                              let bcx = this.bcx;
 331                              let null = C_null(llptrty);
 332                              let ptr = adt::trans_field_ptr(bcx, &*repr, null, v.disr_val, j);
 333                              let offset = p2i(ccx, ptr);
 334                              let field_args = [this.c_uint(j),
 335                                                 offset,
 336                                                 this.c_tydesc(*a)];
 337                              this.visit("enum_variant_field",
 338                                         field_args);
 339                          }
 340                      })
 341                  }
 342              })
 343            }
 344  
 345            ty::ty_trait(..) => {
 346                let extra = [
 347                    self.c_slice(token::intern_and_get_ident(ty_to_str(tcx, t)))
 348                ];
 349                self.visit("trait", extra);
 350            }
 351  
 352            // Miscellaneous extra types
 353            ty::ty_infer(_) => self.leaf("infer"),
 354            ty::ty_err => self.leaf("err"),
 355            ty::ty_param(ref p) => {
 356                let extra = vec!(self.c_uint(p.idx));
 357                self.visit("param", extra.as_slice())
 358            }
 359            ty::ty_self(..) => self.leaf("self")
 360          }
 361      }
 362  
 363      pub fn visit_sig(&mut self, retvaluint, sig&ty::FnSig) {
 364          for (i, arg) in sig.inputs.iter().enumerate() {
 365              let modeval = 5u;   // "by copy"
 366              let extra = vec!(self.c_uint(i),
 367                           self.c_uint(modeval),
 368                           self.c_tydesc(*arg));
 369              self.visit("fn_input", extra.as_slice());
 370          }
 371          let extra = vec!(self.c_uint(retval),
 372                        self.c_bool(sig.variadic),
 373                        self.c_tydesc(sig.output));
 374          self.visit("fn_output", extra.as_slice());
 375      }
 376  }
 377  
 378  // Emit a sequence of calls to visit_ty::visit_foo
 379  pub fn emit_calls_to_trait_visit_ty<'a>(
 380                                      bcx: &'a Block<'a>,
 381                                      tty::t,
 382                                      visitor_valValueRef,
 383                                      visitor_trait_idDefId)
 384                                      -> &'a Block<'a> {
 385      let fcx = bcx.fcx;
 386      let final = fcx.new_temp_block("final");
 387      let tydesc_ty = ty::get_tydesc_ty(bcx.tcx()).unwrap();
 388      let tydesc_ty = type_of(bcx.ccx(), tydesc_ty);
 389      let visitor_methods = ty::trait_methods(bcx.tcx(), visitor_trait_id);
 390      let mut r = Reflector {
 391          visitor_val: visitor_val,
 392          visitor_methods: visitor_methods.as_slice(),
 393          final_bcx: final,
 394          tydesc_ty: tydesc_ty,
 395          bcx: bcx
 396      };
 397      r.visit_ty(t);
 398      Br(r.bcx, final.llbb);
 399      return final;
 400  }
 401  
 402  pub fn ast_fn_style_constant(fn_styleast::FnStyle) -> uint {
 403      match fn_style {
 404          ast::UnsafeFn => 1u,
 405          ast::NormalFn => 2u,
 406      }
 407  }