rust/src/librustc/middle/trans/reflect.rs

325 lines
12 KiB
Rust
Raw Normal View History

// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::map::HashMap;
2012-09-04 13:54:36 -05:00
use lib::llvm::{TypeRef, ValueRef};
use syntax::ast;
use back::abi;
use common::*;
use build::*;
use base::*;
use type_of::*;
use ast::def_id;
use util::ppaux::ty_to_str;
use datum::*;
use callee::{ArgVals, DontAutorefArg};
use expr::SaveIn;
enum reflector = {
visitor_val: ValueRef,
visitor_methods: @~[ty::method],
final_bcx: block,
tydesc_ty: TypeRef,
mut bcx: block
};
2012-08-07 20:10:06 -05:00
impl reflector {
fn c_uint(u: uint) -> ValueRef {
C_uint(self.bcx.ccx(), u)
}
fn c_int(i: int) -> ValueRef {
C_int(self.bcx.ccx(), i)
}
fn c_slice(s: ~str) -> ValueRef {
let ss = C_estr_slice(self.bcx.ccx(), s);
do_spill_noroot(self.bcx, ss)
}
fn c_size_and_align(t: ty::t) -> ~[ValueRef] {
let tr = type_of::type_of(self.bcx.ccx(), t);
let s = shape::llsize_of_real(self.bcx.ccx(), tr);
let a = shape::llalign_of_min(self.bcx.ccx(), tr);
2012-08-01 19:30:05 -05:00
return ~[self.c_uint(s),
self.c_uint(a)];
}
fn c_tydesc(t: ty::t) -> ValueRef {
let bcx = self.bcx;
2012-07-10 17:25:58 -05:00
let static_ti = get_tydesc(bcx.ccx(), t);
glue::lazily_emit_all_tydesc_glue(bcx.ccx(), static_ti);
2012-07-10 17:25:58 -05:00
PointerCast(bcx, static_ti.tydesc, T_ptr(self.tydesc_ty))
}
fn c_mt(mt: ty::mt) -> ~[ValueRef] {
~[self.c_uint(mt.mutbl as uint),
self.c_tydesc(mt.ty)]
}
fn visit(ty_name: ~str, args: ~[ValueRef]) {
let tcx = self.bcx.tcx();
let mth_idx = ty::method_idx(
2012-07-18 18:18:02 -05:00
tcx.sess.ident_of(~"visit_" + ty_name),
*self.visitor_methods).expect(fmt!("Couldn't find visit method \
for %s", ty_name));
let mth_ty = ty::mk_fn(tcx, self.visitor_methods[mth_idx].fty);
let v = self.visitor_val;
2012-08-22 19:24:52 -05:00
debug!("passing %u args:", vec::len(args));
let bcx = self.bcx;
2012-06-30 18:19:07 -05:00
for args.eachi |i, a| {
debug!("arg %u: %s", i, val_str(bcx.ccx().tn, *a));
}
let bool_ty = ty::mk_bool(tcx);
let scratch = scratch_datum(bcx, bool_ty, false);
2012-10-05 18:55:42 -05:00
// XXX: Should not be vstore_box!
let bcx = callee::trans_call_inner(
self.bcx, None, mth_ty, bool_ty,
|bcx| meth::trans_trait_callee_from_llval(bcx,
mth_ty,
mth_idx,
v,
ty::vstore_box,
ast::sty_by_ref),
ArgVals(args), SaveIn(scratch.val), DontAutorefArg);
let result = scratch.to_value_llval(bcx);
let next_bcx = sub_block(bcx, ~"next");
CondBr(bcx, result, next_bcx.llbb, self.final_bcx.llbb);
self.bcx = next_bcx
}
fn bracketed(bracket_name: ~str, extra: ~[ValueRef],
inner: fn()) {
self.visit(~"enter_" + bracket_name, extra);
inner();
self.visit(~"leave_" + bracket_name, extra);
}
fn vstore_name_and_extra(t: ty::t,
vstore: ty::vstore,
f: fn(~str,~[ValueRef])) {
2012-08-06 14:34:08 -05:00
match vstore {
2012-08-03 21:59:04 -05:00
ty::vstore_fixed(n) => {
let extra = vec::append(~[self.c_uint(n)],
self.c_size_and_align(t));
f(~"fixed", extra)
}
2012-08-03 21:59:04 -05:00
ty::vstore_slice(_) => f(~"slice", ~[]),
ty::vstore_uniq => f(~"uniq", ~[]),
ty::vstore_box => f(~"box", ~[])
}
}
fn leaf(name: ~str) {
self.visit(name, ~[]);
}
// Entrypoint
fn visit_ty(t: ty::t) {
let bcx = self.bcx;
2012-08-22 19:24:52 -05:00
debug!("reflect::visit_ty %s",
ty_to_str(bcx.ccx().tcx, t));
match ty::get(t).sty {
2012-08-03 21:59:04 -05:00
ty::ty_bot => self.leaf(~"bot"),
ty::ty_nil => self.leaf(~"nil"),
ty::ty_bool => self.leaf(~"bool"),
ty::ty_int(ast::ty_i) => self.leaf(~"int"),
ty::ty_int(ast::ty_char) => self.leaf(~"char"),
ty::ty_int(ast::ty_i8) => self.leaf(~"i8"),
ty::ty_int(ast::ty_i16) => self.leaf(~"i16"),
ty::ty_int(ast::ty_i32) => self.leaf(~"i32"),
ty::ty_int(ast::ty_i64) => self.leaf(~"i64"),
ty::ty_uint(ast::ty_u) => self.leaf(~"uint"),
ty::ty_uint(ast::ty_u8) => self.leaf(~"u8"),
ty::ty_uint(ast::ty_u16) => self.leaf(~"u16"),
ty::ty_uint(ast::ty_u32) => self.leaf(~"u32"),
ty::ty_uint(ast::ty_u64) => self.leaf(~"u64"),
ty::ty_float(ast::ty_f) => self.leaf(~"float"),
ty::ty_float(ast::ty_f32) => self.leaf(~"f32"),
ty::ty_float(ast::ty_f64) => self.leaf(~"f64"),
2012-08-03 21:59:04 -05:00
ty::ty_unboxed_vec(mt) => self.visit(~"vec", self.c_mt(mt)),
ty::ty_estr(vst) => {
2012-06-30 18:19:07 -05:00
do self.vstore_name_and_extra(t, vst) |name, extra| {
self.visit(~"estr_" + name, extra)
}
}
2012-08-03 21:59:04 -05:00
ty::ty_evec(mt, vst) => {
2012-06-30 18:19:07 -05:00
do self.vstore_name_and_extra(t, vst) |name, extra| {
self.visit(~"evec_" + name, extra +
self.c_mt(mt))
}
}
2012-08-03 21:59:04 -05:00
ty::ty_box(mt) => self.visit(~"box", self.c_mt(mt)),
ty::ty_uniq(mt) => self.visit(~"uniq", self.c_mt(mt)),
ty::ty_ptr(mt) => self.visit(~"ptr", self.c_mt(mt)),
ty::ty_rptr(_, mt) => self.visit(~"rptr", self.c_mt(mt)),
2012-08-03 21:59:04 -05:00
ty::ty_rec(fields) => {
do self.bracketed(~"rec",
~[self.c_uint(vec::len(fields))]
+ self.c_size_and_align(t)) {
for fields.eachi |i, field| {
self.visit(~"rec_field",
~[self.c_uint(i),
2012-07-18 18:18:02 -05:00
self.c_slice(
bcx.ccx().sess.str_of(field.ident))]
+ self.c_mt(field.mt));
}
}
}
2012-08-03 21:59:04 -05:00
ty::ty_tup(tys) => {
do self.bracketed(~"tup",
~[self.c_uint(vec::len(tys))]
+ self.c_size_and_align(t)) {
for tys.eachi |i, t| {
self.visit(~"tup_field",
~[self.c_uint(i),
self.c_tydesc(*t)]);
}
}
}
// FIXME (#2594): fetch constants out of intrinsic:: for the
// numbers.
2012-09-07 09:37:19 -05:00
ty::ty_fn(ref fty) => {
let pureval = match fty.meta.purity {
2012-08-03 21:59:04 -05:00
ast::pure_fn => 0u,
ast::unsafe_fn => 1u,
ast::impure_fn => 2u,
ast::extern_fn => 3u
};
let protoval = ast_proto_constant(fty.meta.proto);
2012-09-07 09:37:19 -05:00
let retval = match fty.meta.ret_style {
2012-08-03 21:59:04 -05:00
ast::noreturn => 0u,
ast::return_val => 1u
};
let extra = ~[self.c_uint(pureval),
2012-09-07 09:37:19 -05:00
self.c_uint(protoval),
self.c_uint(vec::len(fty.sig.inputs)),
self.c_uint(retval)];
self.visit(~"enter_fn", extra);
2012-09-07 09:37:19 -05:00
for fty.sig.inputs.eachi |i, arg| {
2012-08-06 14:34:08 -05:00
let modeval = match arg.mode {
2012-08-03 21:59:04 -05:00
ast::infer(_) => 0u,
2012-08-06 14:34:08 -05:00
ast::expl(e) => match e {
2012-08-03 21:59:04 -05:00
ast::by_ref => 1u,
ast::by_val => 2u,
ast::by_move => 4u,
ast::by_copy => 5u
}
};
self.visit(~"fn_input",
~[self.c_uint(i),
self.c_uint(modeval),
self.c_tydesc(arg.ty)]);
}
self.visit(~"fn_output",
~[self.c_uint(retval),
2012-09-07 09:37:19 -05:00
self.c_tydesc(fty.sig.output)]);
self.visit(~"leave_fn", extra);
}
ty::ty_struct(did, ref substs) => {
let bcx = self.bcx;
let tcx = bcx.ccx().tcx;
let fields = ty::struct_fields(tcx, did, substs);
do self.bracketed(~"class", ~[self.c_uint(fields.len())]
+ self.c_size_and_align(t)) {
for fields.eachi |i, field| {
self.visit(~"class_field",
~[self.c_uint(i),
2012-07-18 18:18:02 -05:00
self.c_slice(
bcx.ccx().sess.str_of(field.ident))]
+ self.c_mt(field.mt));
}
}
}
// FIXME (#2595): visiting all the variants in turn is probably
// not ideal. It'll work but will get costly on big enums. Maybe
// let the visitor tell us if it wants to visit only a particular
// variant?
2012-08-10 12:49:31 -05:00
ty::ty_enum(did, ref substs) => {
let bcx = self.bcx;
let tcx = bcx.ccx().tcx;
let variants = ty::substd_enum_variants(tcx, did, substs);
do self.bracketed(~"enum",
~[self.c_uint(vec::len(variants))]
+ self.c_size_and_align(t)) {
for variants.eachi |i, v| {
do self.bracketed(~"enum_variant",
~[self.c_uint(i),
self.c_int(v.disr_val),
self.c_uint(vec::len(v.args)),
2012-07-18 18:18:02 -05:00
self.c_slice(
bcx.ccx().sess.str_of(v.name))]) {
for v.args.eachi |j, a| {
self.visit(~"enum_variant_field",
~[self.c_uint(j),
self.c_tydesc(*a)]);
}
}
}
}
}
// Miscallaneous extra types
ty::ty_trait(_, _, _) => self.leaf(~"trait"),
ty::ty_infer(_) => self.leaf(~"infer"),
ty::ty_err => self.leaf(~"err"),
2012-08-03 21:59:04 -05:00
ty::ty_param(p) => self.visit(~"param", ~[self.c_uint(p.idx)]),
ty::ty_self => self.leaf(~"self"),
ty::ty_type => self.leaf(~"type"),
ty::ty_opaque_box => self.leaf(~"opaque_box"),
ty::ty_opaque_closure_ptr(ck) => {
let ckval = ast_proto_constant(ck);
self.visit(~"closure_ptr", ~[self.c_uint(ckval)])
}
}
}
}
// Emit a sequence of calls to visit_ty::visit_foo
fn emit_calls_to_trait_visit_ty(bcx: block, t: ty::t,
visitor_val: ValueRef,
visitor_trait_id: def_id) -> block {
use syntax::parse::token::special_idents::tydesc;
let final = sub_block(bcx, ~"final");
2012-07-18 18:18:02 -05:00
assert bcx.ccx().tcx.intrinsic_defs.contains_key(tydesc);
let (_, tydesc_ty) = bcx.ccx().tcx.intrinsic_defs.get(tydesc);
let tydesc_ty = type_of::type_of(bcx.ccx(), tydesc_ty);
let r = reflector({
visitor_val: visitor_val,
visitor_methods: ty::trait_methods(bcx.tcx(), visitor_trait_id),
final_bcx: final,
tydesc_ty: tydesc_ty,
mut bcx: bcx
});
r.visit_ty(t);
Br(r.bcx, final.llbb);
2012-08-01 19:30:05 -05:00
return final;
}
fn ast_proto_constant(proto: ast::Proto) -> uint {
match proto {
ast::ProtoBare => 0u,
ast::ProtoUniq => 2u,
ast::ProtoBox => 3u,
ast::ProtoBorrowed => 4u,
}
}