294 lines
10 KiB
Rust
294 lines
10 KiB
Rust
import std::map::{hashmap,str_hash};
|
|
import driver::session::session;
|
|
import lib::llvm::{TypeRef, ValueRef};
|
|
import syntax::ast;
|
|
import back::abi;
|
|
import common::*;
|
|
import build::*;
|
|
import base::*;
|
|
import type_of::*;
|
|
import ast::def_id;
|
|
import util::ppaux::ty_to_str;
|
|
|
|
enum reflector = {
|
|
visitor_val: ValueRef,
|
|
visitor_methods: @~[ty::method],
|
|
mut bcx: block
|
|
};
|
|
|
|
impl methods for 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);
|
|
ret ~[self.c_uint(s),
|
|
self.c_uint(a)];
|
|
}
|
|
|
|
fn visit(ty_name: str, args: ~[ValueRef]) {
|
|
let tcx = self.bcx.tcx();
|
|
let mth_idx = option::get(ty::method_idx(@("visit_" + ty_name),
|
|
*self.visitor_methods));
|
|
let mth_ty = ty::mk_fn(tcx, self.visitor_methods[mth_idx].fty);
|
|
let v = self.visitor_val;
|
|
let get_lval = |bcx| {
|
|
let callee =
|
|
impl::trans_iface_callee(bcx, v, mth_ty, mth_idx);
|
|
#debug("calling mth ty %s, lltype %s",
|
|
ty_to_str(bcx.ccx().tcx, mth_ty),
|
|
val_str(bcx.ccx().tn, callee.val));
|
|
callee
|
|
};
|
|
#debug("passing %u args:", vec::len(args));
|
|
let bcx = self.bcx;
|
|
for args.eachi |i, a| {
|
|
#debug("arg %u: %s", i, val_str(bcx.ccx().tn, a));
|
|
}
|
|
self.bcx =
|
|
trans_call_inner(self.bcx, none, mth_ty, ty::mk_bool(tcx),
|
|
get_lval, arg_vals(args), ignore);
|
|
}
|
|
|
|
fn visit_tydesc(t: ty::t) {
|
|
self.bcx =
|
|
call_tydesc_glue(self.bcx, self.visitor_val, t,
|
|
abi::tydesc_field_visit_glue);
|
|
}
|
|
|
|
fn bracketed_t(bracket_name: str, t: ty::t, extra: ~[ValueRef]) {
|
|
self.visit("enter_" + bracket_name, extra);
|
|
self.visit_tydesc(t);
|
|
self.visit("leave_" + bracket_name, extra);
|
|
}
|
|
|
|
fn bracketed_mt(bracket_name: str, mt: ty::mt, extra: ~[ValueRef]) {
|
|
self.bracketed_t(bracket_name, mt.ty,
|
|
vec::append(~[self.c_uint(mt.mutbl as uint)],
|
|
extra));
|
|
}
|
|
|
|
fn vstore_name_and_extra(t: ty::t,
|
|
vstore: ty::vstore,
|
|
f: fn(str,~[ValueRef])) {
|
|
alt vstore {
|
|
ty::vstore_fixed(n) {
|
|
let extra = vec::append(~[self.c_uint(n)],
|
|
self.c_size_and_align(t));
|
|
f("fixed", extra)
|
|
}
|
|
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;
|
|
#debug("reflect::visit_ty %s",
|
|
ty_to_str(bcx.ccx().tcx, t));
|
|
|
|
alt ty::get(t).struct {
|
|
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") }
|
|
ty::ty_str { self.leaf("str") }
|
|
|
|
ty::ty_vec(mt) { self.bracketed_mt("vec", mt, ~[]) }
|
|
ty::ty_estr(vst) {
|
|
do self.vstore_name_and_extra(t, vst) |name, extra| {
|
|
self.visit("estr_" + name, extra)
|
|
}
|
|
}
|
|
ty::ty_evec(mt, vst) {
|
|
do self.vstore_name_and_extra(t, vst) |name, extra| {
|
|
self.bracketed_mt("evec_" + name, mt, extra)
|
|
}
|
|
}
|
|
ty::ty_box(mt) { self.bracketed_mt("box", mt, ~[]) }
|
|
ty::ty_uniq(mt) { self.bracketed_mt("uniq", mt, ~[]) }
|
|
ty::ty_ptr(mt) { self.bracketed_mt("ptr", mt, ~[]) }
|
|
ty::ty_rptr(_, mt) { self.bracketed_mt("rptr", mt, ~[]) }
|
|
|
|
ty::ty_rec(fields) {
|
|
let extra = (vec::append(~[self.c_uint(vec::len(fields))],
|
|
self.c_size_and_align(t)));
|
|
self.visit("enter_rec", extra);
|
|
for fields.eachi |i, field| {
|
|
self.bracketed_mt("rec_field", field.mt,
|
|
~[self.c_uint(i),
|
|
self.c_slice(*field.ident)]);
|
|
}
|
|
self.visit("leave_rec", extra);
|
|
}
|
|
|
|
ty::ty_tup(tys) {
|
|
let extra = (vec::append(~[self.c_uint(vec::len(tys))],
|
|
self.c_size_and_align(t)));
|
|
self.visit("enter_tup", extra);
|
|
for tys.eachi |i, t| {
|
|
self.bracketed_t("tup_field", t, ~[self.c_uint(i)]);
|
|
}
|
|
self.visit("leave_tup", extra);
|
|
}
|
|
|
|
// FIXME (#2594): fetch constants out of intrinsic:: for the
|
|
// numbers.
|
|
ty::ty_fn(fty) {
|
|
let pureval = alt fty.purity {
|
|
ast::pure_fn { 0u }
|
|
ast::unsafe_fn { 1u }
|
|
ast::impure_fn { 2u }
|
|
ast::extern_fn { 3u }
|
|
};
|
|
let protoval = alt fty.proto {
|
|
ast::proto_bare { 0u }
|
|
ast::proto_any { 1u }
|
|
ast::proto_uniq { 2u }
|
|
ast::proto_box { 3u }
|
|
ast::proto_block { 4u }
|
|
};
|
|
let retval = alt fty.ret_style {
|
|
ast::noreturn { 0u }
|
|
ast::return_val { 1u }
|
|
};
|
|
let extra = ~[self.c_uint(pureval),
|
|
self.c_uint(protoval),
|
|
self.c_uint(vec::len(fty.inputs)),
|
|
self.c_uint(retval)];
|
|
self.visit("enter_fn", extra);
|
|
for fty.inputs.eachi |i, arg| {
|
|
let modeval = alt arg.mode {
|
|
ast::infer(_) { 0u }
|
|
ast::expl(e) {
|
|
alt e {
|
|
ast::by_ref { 1u }
|
|
ast::by_val { 2u }
|
|
ast::by_mutbl_ref { 3u }
|
|
ast::by_move { 4u }
|
|
ast::by_copy { 5u }
|
|
}
|
|
}
|
|
};
|
|
self.bracketed_t("fn_input", arg.ty,
|
|
~[self.c_uint(i),
|
|
self.c_uint(modeval)]);
|
|
}
|
|
self.bracketed_t("fn_output", fty.output,
|
|
~[self.c_uint(retval)]);
|
|
self.visit("leave_fn", extra);
|
|
}
|
|
|
|
ty::ty_class(did, substs) {
|
|
let bcx = self.bcx;
|
|
let tcx = bcx.ccx().tcx;
|
|
let fields = ty::class_items_as_fields(tcx, did, substs);
|
|
let extra = vec::append(~[self.c_uint(vec::len(fields))],
|
|
self.c_size_and_align(t));
|
|
|
|
self.visit("enter_class", extra);
|
|
for fields.eachi |i, field| {
|
|
self.bracketed_mt("class_field", field.mt,
|
|
~[self.c_uint(i),
|
|
self.c_slice(*field.ident)]);
|
|
}
|
|
self.visit("leave_class", extra);
|
|
}
|
|
|
|
// 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?
|
|
ty::ty_enum(did, substs) {
|
|
let bcx = self.bcx;
|
|
let tcx = bcx.ccx().tcx;
|
|
let variants = ty::substd_enum_variants(tcx, did, substs);
|
|
let extra = vec::append(~[self.c_uint(vec::len(variants))],
|
|
self.c_size_and_align(t));
|
|
|
|
self.visit("enter_enum", extra);
|
|
for variants.eachi |i, v| {
|
|
let extra = ~[self.c_uint(i),
|
|
self.c_int(v.disr_val),
|
|
self.c_uint(vec::len(v.args)),
|
|
self.c_slice(*v.name)];
|
|
self.visit("enter_enum_variant", extra);
|
|
for v.args.eachi |j, a| {
|
|
self.bracketed_t("enum_variant_field", a,
|
|
~[self.c_uint(j)]);
|
|
}
|
|
self.visit("leave_enum_variant", extra);
|
|
}
|
|
self.visit("leave_enum", extra);
|
|
}
|
|
|
|
// Miscallaneous extra types
|
|
ty::ty_iface(_, _) { self.leaf("iface") }
|
|
ty::ty_var(_) { self.leaf("var") }
|
|
ty::ty_var_integral(_) { self.leaf("var_integral") }
|
|
ty::ty_param(n, _) { self.visit("param", ~[self.c_uint(n)]) }
|
|
ty::ty_self { self.leaf("self") }
|
|
ty::ty_type { self.leaf("type") }
|
|
ty::ty_opaque_box { self.leaf("opaque_box") }
|
|
ty::ty_constr(t, _) { self.bracketed_t("constr", t, ~[]) }
|
|
ty::ty_opaque_closure_ptr(ck) {
|
|
let ckval = alt ck {
|
|
ty::ck_block { 0u }
|
|
ty::ck_box { 1u }
|
|
ty::ck_uniq { 2u }
|
|
};
|
|
self.visit("closure_ptr", ~[self.c_uint(ckval)])
|
|
}
|
|
ty::ty_unboxed_vec(mt) { self.bracketed_mt("vec", mt, ~[]) }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Emit a sequence of calls to visit_ty::visit_foo
|
|
fn emit_calls_to_iface_visit_ty(bcx: block, t: ty::t,
|
|
visitor_val: ValueRef,
|
|
visitor_iid: def_id) -> block {
|
|
|
|
let r = reflector({
|
|
visitor_val: visitor_val,
|
|
visitor_methods: ty::iface_methods(bcx.tcx(), visitor_iid),
|
|
mut bcx: bcx
|
|
});
|
|
|
|
r.visit_ty(t);
|
|
ret r.bcx;
|
|
}
|