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("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, 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".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, retval: uint, 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 t: ty::t,
382 visitor_val: ValueRef,
383 visitor_trait_id: DefId)
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_style: ast::FnStyle) -> uint {
403 match fn_style {
404 ast::UnsafeFn => 1u,
405 ast::NormalFn => 2u,
406 }
407 }