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