]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/reflect.rs
Merge remote-tracking branch 'remotes/origin/master' into str-remove-null
[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, DontAutorefArg};
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_of::*;
24 use middle::ty;
25 use util::ppaux::ty_to_str;
26
27 use std::libc::c_uint;
28 use std::option::None;
29 use std::vec;
30 use syntax::ast::def_id;
31 use syntax::ast;
32 use syntax::ast_map::path_name;
33 use syntax::parse::token::special_idents;
34
35 use middle::trans::type_::Type;
36
37 pub struct Reflector {
38     visitor_val: ValueRef,
39     visitor_methods: @~[@ty::Method],
40     final_bcx: @mut Block,
41     tydesc_ty: Type,
42     bcx: @mut Block
43 }
44
45 impl Reflector {
46     pub fn c_uint(&mut self, u: uint) -> ValueRef {
47         C_uint(self.bcx.ccx(), u)
48     }
49
50     pub fn c_int(&mut self, i: int) -> ValueRef {
51         C_int(self.bcx.ccx(), i)
52     }
53
54     pub fn c_slice(&mut self, s: @str) -> 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_vstore = ty::vstore_slice(ty::re_static);
59         let str_ty = ty::mk_estr(bcx.tcx(), str_vstore);
60         let scratch = scratch_datum(bcx, str_ty, "", false);
61         let len = C_uint(bcx.ccx(), s.len());
62         let c_str = PointerCast(bcx, C_cstr(bcx.ccx(), s), Type::i8p());
63         Store(bcx, c_str, GEPi(bcx, scratch.val, [ 0, 0 ]));
64         Store(bcx, len, GEPi(bcx, scratch.val, [ 0, 1 ]));
65         scratch.val
66     }
67
68     pub fn c_size_and_align(&mut self, t: ty::t) -> ~[ValueRef] {
69         let tr = type_of(self.bcx.ccx(), t);
70         let s = machine::llsize_of_real(self.bcx.ccx(), tr);
71         let a = machine::llalign_of_min(self.bcx.ccx(), tr);
72         return ~[self.c_uint(s),
73              self.c_uint(a)];
74     }
75
76     pub fn c_tydesc(&mut self, t: ty::t) -> ValueRef {
77         let bcx = self.bcx;
78         let static_ti = get_tydesc(bcx.ccx(), t);
79         glue::lazily_emit_all_tydesc_glue(bcx.ccx(), static_ti);
80         PointerCast(bcx, static_ti.tydesc, self.tydesc_ty.ptr_to())
81     }
82
83     pub fn c_mt(&mut self, mt: &ty::mt) -> ~[ValueRef] {
84         ~[self.c_uint(mt.mutbl as uint),
85           self.c_tydesc(mt.ty)]
86     }
87
88     pub fn visit(&mut self, ty_name: &str, args: &[ValueRef]) {
89         let tcx = self.bcx.tcx();
90         let mth_idx = ty::method_idx(
91             tcx.sess.ident_of(~"visit_" + ty_name),
92             *self.visitor_methods).expect(fmt!("Couldn't find visit method \
93                                                 for %s", ty_name));
94         let mth_ty =
95             ty::mk_bare_fn(tcx, self.visitor_methods[mth_idx].fty.clone());
96         let v = self.visitor_val;
97         debug!("passing %u args:", args.len());
98         let mut bcx = self.bcx;
99         for (i, a) in args.iter().enumerate() {
100             debug!("arg %u: %s", i, bcx.val_to_str(*a));
101         }
102         let bool_ty = ty::mk_bool();
103         // XXX: Should not be BoxTraitStore!
104         let result = unpack_result!(bcx, callee::trans_call_inner(
105             self.bcx, None, mth_ty, bool_ty,
106             |bcx| meth::trans_trait_callee_from_llval(bcx,
107                                                       mth_ty,
108                                                       mth_idx,
109                                                       v,
110                                                       ty::BoxTraitStore,
111                                                       ast::sty_region(
112                                                         None,
113                                                         ast::m_imm)),
114             ArgVals(args), None, DontAutorefArg));
115         let result = bool_to_i1(bcx, result);
116         let next_bcx = sub_block(bcx, "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: &fn(&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             ty::vstore_box => (~"box", ~[])
143         }
144     }
145
146     pub fn leaf(&mut self, name: &str) {
147         self.visit(name, []);
148     }
149
150     // Entrypoint
151     pub fn visit_ty(&mut self, t: ty::t) {
152         let bcx = self.bcx;
153         debug!("reflect::visit_ty %s", 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_int(ast::ty_i) => self.leaf("int"),
160           ty::ty_int(ast::ty_char) => self.leaf("char"),
161           ty::ty_int(ast::ty_i8) => self.leaf("i8"),
162           ty::ty_int(ast::ty_i16) => self.leaf("i16"),
163           ty::ty_int(ast::ty_i32) => self.leaf("i32"),
164           ty::ty_int(ast::ty_i64) => self.leaf("i64"),
165           ty::ty_uint(ast::ty_u) => self.leaf("uint"),
166           ty::ty_uint(ast::ty_u8) => self.leaf("u8"),
167           ty::ty_uint(ast::ty_u16) => self.leaf("u16"),
168           ty::ty_uint(ast::ty_u32) => self.leaf("u32"),
169           ty::ty_uint(ast::ty_u64) => self.leaf("u64"),
170           ty::ty_float(ast::ty_f) => self.leaf("float"),
171           ty::ty_float(ast::ty_f32) => self.leaf("f32"),
172           ty::ty_float(ast::ty_f64) => self.leaf("f64"),
173
174           ty::ty_unboxed_vec(ref mt) => {
175               let values = self.c_mt(mt);
176               self.visit("vec", values)
177           }
178
179           ty::ty_estr(vst) => {
180               let (name, extra) = self.vstore_name_and_extra(t, vst);
181               self.visit(~"estr_" + name, extra)
182           }
183           ty::ty_evec(ref mt, vst) => {
184               let (name, extra) = self.vstore_name_and_extra(t, vst);
185               let extra = extra + self.c_mt(mt);
186               if "uniq" == name && ty::type_contents(bcx.tcx(), t).contains_managed() {
187                   self.visit("evec_uniq_managed", extra)
188               } else {
189                   self.visit(~"evec_" + name, extra)
190               }
191           }
192           ty::ty_box(ref mt) => {
193               let extra = self.c_mt(mt);
194               self.visit("box", extra)
195           }
196           ty::ty_uniq(ref mt) => {
197               let extra = self.c_mt(mt);
198               if ty::type_contents(bcx.tcx(), t).contains_managed() {
199                   self.visit("uniq_managed", extra)
200               } else {
201                   self.visit("uniq", extra)
202               }
203           }
204           ty::ty_ptr(ref mt) => {
205               let extra = self.c_mt(mt);
206               self.visit("ptr", extra)
207           }
208           ty::ty_rptr(_, ref mt) => {
209               let extra = self.c_mt(mt);
210               self.visit("rptr", extra)
211           }
212
213           ty::ty_tup(ref tys) => {
214               let extra = ~[self.c_uint(tys.len())]
215                   + self.c_size_and_align(t);
216               do self.bracketed("tup", extra) |this| {
217                   for (i, t) in tys.iter().enumerate() {
218                       let extra = ~[this.c_uint(i), this.c_tydesc(*t)];
219                       this.visit("tup_field", extra);
220                   }
221               }
222           }
223
224           // FIXME (#2594): fetch constants out of intrinsic
225           // FIXME (#4809): visitor should break out bare fns from other fns
226           ty::ty_closure(ref fty) => {
227             let pureval = ast_purity_constant(fty.purity);
228             let sigilval = ast_sigil_constant(fty.sigil);
229             let retval = if ty::type_is_bot(fty.sig.output) {0u} else {1u};
230             let extra = ~[self.c_uint(pureval),
231                           self.c_uint(sigilval),
232                           self.c_uint(fty.sig.inputs.len()),
233                           self.c_uint(retval)];
234             self.visit("enter_fn", extra);
235             self.visit_sig(retval, &fty.sig);
236             self.visit("leave_fn", extra);
237           }
238
239           // FIXME (#2594): fetch constants out of intrinsic:: for the
240           // numbers.
241           ty::ty_bare_fn(ref fty) => {
242             let pureval = ast_purity_constant(fty.purity);
243             let sigilval = 0u;
244             let retval = if ty::type_is_bot(fty.sig.output) {0u} else {1u};
245             let extra = ~[self.c_uint(pureval),
246                           self.c_uint(sigilval),
247                           self.c_uint(fty.sig.inputs.len()),
248                           self.c_uint(retval)];
249             self.visit("enter_fn", extra);
250             self.visit_sig(retval, &fty.sig);
251             self.visit("leave_fn", extra);
252           }
253
254           ty::ty_struct(did, ref substs) => {
255               let bcx = self.bcx;
256               let tcx = bcx.ccx().tcx;
257               let fields = ty::struct_fields(tcx, did, substs);
258
259               let extra = ~[self.c_uint(fields.len())]
260                   + self.c_size_and_align(t);
261               do self.bracketed("class", extra) |this| {
262                   for (i, field) in fields.iter().enumerate() {
263                       let extra = ~[this.c_uint(i),
264                                     this.c_slice(
265                                         bcx.ccx().sess.str_of(field.ident))]
266                           + this.c_mt(&field.mt);
267                       this.visit("class_field", extra);
268                   }
269               }
270           }
271
272           // FIXME (#2595): visiting all the variants in turn is probably
273           // not ideal. It'll work but will get costly on big enums. Maybe
274           // let the visitor tell us if it wants to visit only a particular
275           // variant?
276           ty::ty_enum(did, ref substs) => {
277             let bcx = self.bcx;
278             let ccx = bcx.ccx();
279             let repr = adt::represent_type(bcx.ccx(), t);
280             let variants = ty::substd_enum_variants(ccx.tcx, did, substs);
281             let llptrty = type_of(ccx, t).ptr_to();
282             let opaquety = ty::get_opaque_ty(ccx.tcx).unwrap();
283             let opaqueptrty = ty::mk_ptr(ccx.tcx, ty::mt { ty: opaquety, mutbl: ast::m_imm });
284
285             let make_get_disr = || {
286                 let sub_path = bcx.fcx.path + &[path_name(special_idents::anon)];
287                 let sym = mangle_internal_name_by_path_and_seq(ccx,
288                                                                sub_path,
289                                                                "get_disr");
290
291                 let llfty = type_of_fn(ccx, [opaqueptrty], ty::mk_int());
292                 let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
293                 let fcx = new_fn_ctxt(ccx,
294                                       ~[],
295                                       llfdecl,
296                                       ty::mk_uint(),
297                                       None);
298                 let arg = unsafe {
299                     //
300                     // we know the return type of llfdecl is an int here, so
301                     // no need for a special check to see if the return type
302                     // is immediate.
303                     //
304                     llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
305                 };
306                 let mut bcx = fcx.entry_bcx.get();
307                 let arg = BitCast(bcx, arg, llptrty);
308                 let ret = adt::trans_get_discr(bcx, repr, arg);
309                 Store(bcx, ret, fcx.llretptr.get());
310                 match fcx.llreturn {
311                     Some(llreturn) => cleanup_and_Br(bcx, bcx, llreturn),
312                     None => bcx = cleanup_block(bcx, Some(bcx.llbb))
313                 };
314                 finish_fn(fcx, bcx);
315                 llfdecl
316             };
317
318             let enum_args = ~[self.c_uint(variants.len()), make_get_disr()]
319                 + self.c_size_and_align(t);
320             do self.bracketed("enum", enum_args) |this| {
321                 for (i, v) in variants.iter().enumerate() {
322                     let name = ccx.sess.str_of(v.name);
323                     let variant_args = ~[this.c_uint(i),
324                                          this.c_uint(v.disr_val),
325                                          this.c_uint(v.args.len()),
326                                          this.c_slice(name)];
327                     do this.bracketed("enum_variant", variant_args) |this| {
328                         for (j, a) in v.args.iter().enumerate() {
329                             let bcx = this.bcx;
330                             let null = C_null(llptrty);
331                             let ptr = adt::trans_field_ptr(bcx, repr, null, v.disr_val, j);
332                             let offset = p2i(ccx, ptr);
333                             let field_args = ~[this.c_uint(j),
334                                                offset,
335                                                this.c_tydesc(*a)];
336                             this.visit("enum_variant_field", field_args);
337                         }
338                     }
339                 }
340             }
341           }
342
343           // Miscallaneous extra types
344           ty::ty_trait(_, _, _, _, _) => self.leaf("trait"),
345           ty::ty_infer(_) => self.leaf("infer"),
346           ty::ty_err => self.leaf("err"),
347           ty::ty_param(ref p) => {
348               let extra = ~[self.c_uint(p.idx)];
349               self.visit("param", extra)
350           }
351           ty::ty_self(*) => self.leaf("self"),
352           ty::ty_type => self.leaf("type"),
353           ty::ty_opaque_box => self.leaf("opaque_box"),
354           ty::ty_opaque_closure_ptr(ck) => {
355               let ckval = ast_sigil_constant(ck);
356               let extra = ~[self.c_uint(ckval)];
357               self.visit("closure_ptr", extra)
358           }
359         }
360     }
361
362     pub fn visit_sig(&mut self, retval: uint, sig: &ty::FnSig) {
363         for (i, arg) in sig.inputs.iter().enumerate() {
364             let modeval = 5u;   // "by copy"
365             let extra = ~[self.c_uint(i),
366                          self.c_uint(modeval),
367                          self.c_tydesc(*arg)];
368             self.visit("fn_input", extra);
369         }
370         let extra = ~[self.c_uint(retval),
371                       self.c_tydesc(sig.output)];
372         self.visit("fn_output", extra);
373     }
374 }
375
376 // Emit a sequence of calls to visit_ty::visit_foo
377 pub fn emit_calls_to_trait_visit_ty(bcx: @mut Block,
378                                     t: ty::t,
379                                     visitor_val: ValueRef,
380                                     visitor_trait_id: def_id)
381                                  -> @mut Block {
382     let final = sub_block(bcx, "final");
383     let tydesc_ty = ty::get_tydesc_ty(bcx.ccx().tcx).unwrap();
384     let tydesc_ty = type_of(bcx.ccx(), tydesc_ty);
385     let mut r = Reflector {
386         visitor_val: visitor_val,
387         visitor_methods: ty::trait_methods(bcx.tcx(), visitor_trait_id),
388         final_bcx: final,
389         tydesc_ty: tydesc_ty,
390         bcx: bcx
391     };
392     r.visit_ty(t);
393     Br(r.bcx, final.llbb);
394     return final;
395 }
396
397 pub fn ast_sigil_constant(sigil: ast::Sigil) -> uint {
398     match sigil {
399         ast::OwnedSigil => 2u,
400         ast::ManagedSigil => 3u,
401         ast::BorrowedSigil => 4u,
402     }
403 }
404
405 pub fn ast_purity_constant(purity: ast::purity) -> uint {
406     match purity {
407         ast::unsafe_fn => 1u,
408         ast::impure_fn => 2u,
409         ast::extern_fn => 3u
410     }
411 }