]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/reflect.rs
59903324e10eaaf2c5c6b2061eb59df0ff6e659d
[rust.git] / src / librustc / middle / trans / reflect.rs
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, u: uint) -> ValueRef {
47         C_uint(self.bcx.ccx(), u)
48     }
49
50     pub fn c_bool(&mut self, b: bool) -> ValueRef {
51         C_bool(self.bcx.ccx(), b)
52     }
53
54     pub fn c_slice(&mut self, s: InternedString) -> 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, t: ty::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, t: ty::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(format!(
91                         "visit_{}", ty_name).as_slice()),
92                                      self.visitor_methods.as_slice()).expect(
93                 format!("couldn't find visit method for {}", ty_name).as_slice());
94         let mth_ty =
95             ty::mk_bare_fn(tcx,
96                            self.visitor_methods[mth_idx].fty.clone());
97         let v = self.visitor_val;
98         debug!("passing {} args:", args.len());
99         let mut bcx = self.bcx;
100         for (i, a) in args.iter().enumerate() {
101             debug!("arg {}: {}", i, bcx.val_to_str(*a));
102         }
103         let result = unpack_result!(bcx, callee::trans_call_inner(
104             self.bcx, None, mth_ty,
105             |bcx, _| meth::trans_trait_callee_from_llval(bcx,
106                                                          mth_ty,
107                                                          mth_idx,
108                                                          v),
109             ArgVals(args), None));
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(format!("enter_{}", bracket_name).as_slice(), extra);
120         inner(self);
121         self.visit(format!("leave_{}", bracket_name).as_slice(), 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, t: ty::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", extra.as_slice())
158           }
159           ty::ty_vec(..) | ty::ty_str | ty::ty_trait(..) => 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", extra.as_slice())
174                   }
175                   ty::ty_str => self.visit("estr_uniq", &[]),
176                   ty::ty_trait(..) => {
177                       let extra = [
178                           self.c_slice(token::intern_and_get_ident(
179                                   ty_to_str(tcx, t).as_slice()))
180                       ];
181                       self.visit("trait", extra);
182                   }
183                   _ => {
184                       let extra = self.c_mt(&ty::mt {
185                           ty: typ,
186                           mutbl: ast::MutImmutable,
187                       });
188                       self.visit("uniq", extra.as_slice())
189                   }
190               }
191           }
192           ty::ty_ptr(ref mt) => {
193               let extra = self.c_mt(mt);
194               self.visit("ptr", extra.as_slice())
195           }
196           ty::ty_rptr(_, ref mt) => {
197               match ty::get(mt.ty).sty {
198                   ty::ty_vec(ref mt, None) => {
199                       let (name, extra) = ("slice".to_string(), Vec::new());
200                       let extra = extra.append(self.c_mt(mt).as_slice());
201                       self.visit(format!("evec_{}", name).as_slice(),
202                                  extra.as_slice())
203                   }
204                   ty::ty_str => self.visit("estr_slice", &[]),
205                   ty::ty_trait(..) => {
206                       let extra = [
207                           self.c_slice(token::intern_and_get_ident(
208                                   ty_to_str(tcx, t).as_slice()))
209                       ];
210                       self.visit("trait", extra);
211                   }
212                   _ => {
213                       let extra = self.c_mt(mt);
214                       self.visit("rptr", extra.as_slice())
215                   }
216               }
217           }
218
219           ty::ty_tup(ref tys) => {
220               let extra = (vec!(self.c_uint(tys.len())))
221                           .append(self.c_size_and_align(t).as_slice());
222               self.bracketed("tup", extra.as_slice(), |this| {
223                   for (i, t) in tys.iter().enumerate() {
224                       let extra = vec!(this.c_uint(i), this.c_tydesc(*t));
225                       this.visit("tup_field", extra.as_slice());
226                   }
227               })
228           }
229
230           // FIXME (#2594): fetch constants out of intrinsic
231           // FIXME (#4809): visitor should break out bare fns from other fns
232           ty::ty_closure(ref fty) => {
233             let pureval = ast_fn_style_constant(fty.fn_style);
234             let sigilval = match fty.store {
235                 ty::UniqTraitStore => 2u,
236                 ty::RegionTraitStore(..) => 4u,
237             };
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           // FIXME (#2594): fetch constants out of intrinsic:: for the
249           // numbers.
250           ty::ty_bare_fn(ref fty) => {
251             let pureval = ast_fn_style_constant(fty.fn_style);
252             let sigilval = 0u;
253             let retval = if ty::type_is_bot(fty.sig.output) {0u} else {1u};
254             let extra = vec!(self.c_uint(pureval),
255                           self.c_uint(sigilval),
256                           self.c_uint(fty.sig.inputs.len()),
257                           self.c_uint(retval));
258             self.visit("enter_fn", extra.as_slice());
259             self.visit_sig(retval, &fty.sig);
260             self.visit("leave_fn", extra.as_slice());
261           }
262
263           ty::ty_struct(did, ref substs) => {
264               let fields = ty::struct_fields(tcx, did, substs);
265               let mut named_fields = false;
266               if !fields.is_empty() {
267                   named_fields = fields.get(0).ident.name !=
268                       special_idents::unnamed_field.name;
269               }
270
271               let extra = (vec!(
272                   self.c_slice(
273                       token::intern_and_get_ident(ty_to_str(tcx,
274                                                             t).as_slice())),
275                   self.c_bool(named_fields),
276                   self.c_uint(fields.len())
277               )).append(self.c_size_and_align(t).as_slice());
278               self.bracketed("class", extra.as_slice(), |this| {
279                   for (i, field) in fields.iter().enumerate() {
280                       let extra = (vec!(
281                         this.c_uint(i),
282                         this.c_slice(token::get_ident(field.ident)),
283                         this.c_bool(named_fields)
284                       )).append(this.c_mt(&field.mt).as_slice());
285                       this.visit("class_field", extra.as_slice());
286                   }
287               })
288           }
289
290           // FIXME (#2595): visiting all the variants in turn is probably
291           // not ideal. It'll work but will get costly on big enums. Maybe
292           // let the visitor tell us if it wants to visit only a particular
293           // variant?
294           ty::ty_enum(did, ref substs) => {
295             let ccx = bcx.ccx();
296             let repr = adt::represent_type(bcx.ccx(), t);
297             let variants = ty::substd_enum_variants(ccx.tcx(), did, substs);
298             let llptrty = type_of(ccx, t).ptr_to();
299             let opaquety = ty::get_opaque_ty(ccx.tcx()).unwrap();
300             let opaqueptrty = ty::mk_ptr(ccx.tcx(), ty::mt { ty: opaquety,
301                                                            mutbl: ast::MutImmutable });
302
303             let make_get_disr = || {
304                 let sym = mangle_internal_name_by_path_and_seq(
305                     ast_map::Values([].iter()).chain(None), "get_disr");
306
307                 let fn_ty = ty::mk_ctor_fn(&ccx.tcx, ast::DUMMY_NODE_ID,
308                                            [opaqueptrty], ty::mk_u64());
309                 let llfdecl = decl_internal_rust_fn(ccx,
310                                                     fn_ty,
311                                                     sym.as_slice());
312                 let arena = TypedArena::new();
313                 let empty_param_substs = param_substs::empty();
314                 let fcx = new_fn_ctxt(ccx, llfdecl, -1, false,
315                                       ty::mk_u64(), &empty_param_substs,
316                                       None, &arena);
317                 init_function(&fcx, false, ty::mk_u64());
318
319                 let arg = unsafe {
320                     //
321                     // we know the return type of llfdecl is an int here, so
322                     // no need for a special check to see if the return type
323                     // is immediate.
324                     //
325                     llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
326                 };
327                 let bcx = fcx.entry_bcx.borrow().clone().unwrap();
328                 let arg = BitCast(bcx, arg, llptrty);
329                 let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
330                 Store(bcx, ret, fcx.llretptr.get().unwrap());
331                 match fcx.llreturn.get() {
332                     Some(llreturn) => Br(bcx, llreturn),
333                     None => {}
334                 };
335                 finish_fn(&fcx, bcx);
336                 llfdecl
337             };
338
339             let enum_args = (vec!(self.c_uint(variants.len()), make_get_disr()))
340                             .append(self.c_size_and_align(t).as_slice());
341             self.bracketed("enum", enum_args.as_slice(), |this| {
342                 for (i, v) in variants.iter().enumerate() {
343                     let name = token::get_ident(v.name);
344                     let variant_args = [this.c_uint(i),
345                                          C_u64(ccx, v.disr_val),
346                                          this.c_uint(v.args.len()),
347                                          this.c_slice(name)];
348                     this.bracketed("enum_variant",
349                                    variant_args,
350                                    |this| {
351                         for (j, a) in v.args.iter().enumerate() {
352                             let bcx = this.bcx;
353                             let null = C_null(llptrty);
354                             let ptr = adt::trans_field_ptr(bcx, &*repr, null, v.disr_val, j);
355                             let offset = p2i(ccx, ptr);
356                             let field_args = [this.c_uint(j),
357                                                offset,
358                                                this.c_tydesc(*a)];
359                             this.visit("enum_variant_field",
360                                        field_args);
361                         }
362                     })
363                 }
364             })
365           }
366
367           // Miscellaneous extra types
368           ty::ty_infer(_) => self.leaf("infer"),
369           ty::ty_err => self.leaf("err"),
370           ty::ty_param(ref p) => {
371               let extra = vec!(self.c_uint(p.idx));
372               self.visit("param", extra.as_slice())
373           }
374         }
375     }
376
377     pub fn visit_sig(&mut self, retval: uint, sig: &ty::FnSig) {
378         for (i, arg) in sig.inputs.iter().enumerate() {
379             let modeval = 5u;   // "by copy"
380             let extra = vec!(self.c_uint(i),
381                          self.c_uint(modeval),
382                          self.c_tydesc(*arg));
383             self.visit("fn_input", extra.as_slice());
384         }
385         let extra = vec!(self.c_uint(retval),
386                       self.c_bool(sig.variadic),
387                       self.c_tydesc(sig.output));
388         self.visit("fn_output", extra.as_slice());
389     }
390 }
391
392 // Emit a sequence of calls to visit_ty::visit_foo
393 pub fn emit_calls_to_trait_visit_ty<'a>(
394                                     bcx: &'a Block<'a>,
395                                     t: ty::t,
396                                     visitor_val: ValueRef,
397                                     visitor_trait_id: DefId)
398                                     -> &'a Block<'a> {
399     let fcx = bcx.fcx;
400     let final = fcx.new_temp_block("final");
401     let tydesc_ty = ty::get_tydesc_ty(bcx.tcx()).unwrap();
402     let tydesc_ty = type_of(bcx.ccx(), tydesc_ty);
403     let visitor_methods = ty::trait_methods(bcx.tcx(), visitor_trait_id);
404     let mut r = Reflector {
405         visitor_val: visitor_val,
406         visitor_methods: visitor_methods.as_slice(),
407         final_bcx: final,
408         tydesc_ty: tydesc_ty,
409         bcx: bcx
410     };
411     r.visit_ty(t);
412     Br(r.bcx, final.llbb);
413     return final;
414 }
415
416 pub fn ast_fn_style_constant(fn_style: ast::FnStyle) -> uint {
417     match fn_style {
418         ast::UnsafeFn => 1u,
419         ast::NormalFn => 2u,
420     }
421 }