Hugely simplify iface handling

With the assumption of monomorphization
This commit is contained in:
Marijn Haverbeke 2012-03-08 16:10:25 +01:00
parent 168398bb3d
commit 4511f936b1
8 changed files with 138 additions and 323 deletions

View file

@ -548,11 +548,14 @@ fn encode_dict_origin(ecx: @e::encode_ctxt,
}
}
}
typeck::dict_iface(def_id) {
typeck::dict_iface(def_id, tys) {
ebml_w.emit_enum_variant("dict_iface", 1u, 3u) {||
ebml_w.emit_enum_variant_arg(0u) {||
ebml_w.emit_def_id(def_id)
}
ebml_w.emit_enum_variant_arg(1u) {||
ebml_w.emit_tys(ecx, tys);
}
}
}
}
@ -596,6 +599,9 @@ impl helpers for ebml::ebml_deserializer {
typeck::dict_iface(
self.read_enum_variant_arg(0u) {||
self.read_def_id(xcx)
},
self.read_enum_variant_arg(1u) {||
self.read_tys(xcx)
}
)
}

View file

@ -258,7 +258,7 @@ fn get_impl_iface(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
}
fn get_impl_method(cdata: cmd, id: ast::node_id, name: str) -> ast::def_id {
let items = ebml::get_doc(ebml::new_doc(cdata.data), tag_items);
let items = ebml::get_doc(ebml::doc(cdata.data), tag_items);
let found = none;
ebml::tagged_docs(find_item(id, items), tag_item_method) {|mid|
let m_did = parse_def_id(ebml::doc_data(mid));

View file

@ -2070,7 +2070,6 @@ enum callee_env {
null_env,
is_closure,
self_env(ValueRef, ty::t),
dict_env(ValueRef, ValueRef),
}
type lval_maybe_callee = {bcx: block,
val: ValueRef,
@ -2117,8 +2116,8 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
}
});
let hash_id = @{def: fn_id, substs: substs, dicts: alt dicts {
some(os) { vec::map(*os, {|o| impl::dict_id(ccx.tcx, o)}) }
none { [] }
some(os) { some_dicts(vec::map(*os, impl::vtable_id)) }
none { no_dicts }
}};
alt ccx.monomorphized.find(hash_id) {
some(val) { ret some(val); }
@ -2258,10 +2257,8 @@ fn lval_static_fn(bcx: block, fn_id: ast::def_id, id: ast::node_id,
none {
alt ccx.maps.dict_map.find(id) {
some(dicts) {
alt impl::resolve_dicts_in_fn_ctxt(bcx.fcx, dicts) {
some(dicts) { monomorphic_fn(ccx, fn_id, tys, some(dicts)) }
none { none }
}
let rdicts = impl::resolve_vtables_in_fn_ctxt(bcx.fcx, dicts);
monomorphic_fn(ccx, fn_id, tys, some(rdicts))
}
none { monomorphic_fn(ccx, fn_id, tys, none) }
}
@ -2567,7 +2564,7 @@ fn trans_lval(cx: block, e: @ast::expr) -> lval_result {
fn lval_maybe_callee_to_lval(c: lval_maybe_callee, ty: ty::t) -> lval_result {
let must_bind = alt c.generic { generic_full(_) { true } _ { false } } ||
alt c.env { self_env(_, _) | dict_env(_, _) { true } _ { false } };
alt c.env { self_env(_, _) { true } _ { false } };
if must_bind {
let n_args = ty::ty_fn_args(ty).len();
let args = vec::from_elem(n_args, none);
@ -2779,28 +2776,7 @@ fn trans_args(cx: block, llenv: ValueRef,
let retty = ty::ty_fn_ret(fn_ty), full_retty = retty;
alt gen {
generic_full(g) {
lazily_emit_all_generic_info_tydesc_glues(ccx, g);
let i = 0u, n_orig = 0u;
for param in *g.param_bounds {
lltydescs += [g.tydescs[i]];
for bound in *param {
alt bound {
ty::bound_iface(_) {
let res = impl::get_dict(
bcx, option::get(g.origins)[n_orig]);
lltydescs += [res.val];
bcx = res.bcx;
n_orig += 1u;
}
_ {}
}
}
i += 1u;
}
args = ty::ty_fn_args(g.item_type);
retty = ty::ty_fn_ret(g.item_type);
}
generic_full(g) { fail; }
generic_mono(t) {
args = ty::ty_fn_args(t);
retty = ty::ty_fn_ret(t);
@ -2884,17 +2860,12 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t,
let bcx = f_res.bcx, ccx = cx.ccx();
let faddr = f_res.val;
let llenv, dict_param = none;
alt f_res.env {
let llenv = alt f_res.env {
null_env {
llenv = llvm::LLVMGetUndef(T_opaque_box_ptr(ccx));
llvm::LLVMGetUndef(T_opaque_box_ptr(ccx))
}
self_env(e, _) {
llenv = PointerCast(bcx, e, T_opaque_box_ptr(ccx));
}
dict_env(dict, e) {
llenv = PointerCast(bcx, e, T_opaque_box_ptr(ccx));
dict_param = some(dict);
PointerCast(bcx, e, T_opaque_box_ptr(ccx))
}
is_closure {
// It's a closure. Have to fetch the elements
@ -2905,16 +2876,15 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t,
faddr = GEPi(bcx, pair, [0, abi::fn_field_code]);
faddr = Load(bcx, faddr);
let llclosure = GEPi(bcx, pair, [0, abi::fn_field_box]);
llenv = Load(bcx, llclosure);
Load(bcx, llclosure)
}
}
};
let ret_ty = node_id_type(bcx, id);
let args_res =
trans_args(bcx, llenv, f_res.generic, args, fn_expr_ty, dest);
bcx = args_res.bcx;
let llargs = args_res.args;
option::may(dict_param) {|dict| llargs = [dict] + llargs}
let llretslot = args_res.retslot;
/* If the block is terminated,
@ -2955,6 +2925,10 @@ fn invoke_(bcx: block, llfn: ValueRef, llargs: [ValueRef],
// cleanups to run
if bcx.unreachable { ret bcx; }
let normal_bcx = sub_block(bcx, "normal return");
/*std::io::println("fn: " + lib::llvm::type_to_str(bcx.ccx().tn, val_ty(llfn)));
for a in llargs {
std::io::println(" a: " + lib::llvm::type_to_str(bcx.ccx().tn, val_ty(a)));
}*/
invoker(bcx, llfn, llargs, normal_bcx.llbb, get_landing_pad(bcx));
ret normal_bcx;
}
@ -4791,16 +4765,6 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
i += 1;
}
}
ast::item_impl(tps, some(@{node: ast::ty_path(_, id), _}), _, ms) {
let i_did = ast_util::def_id_of_def(ccx.tcx.def_map.get(id));
impl::trans_impl_vtable(ccx, item_path(ccx, it), i_did, ms, tps, it);
}
ast::item_iface(_, _) {
if !vec::any(*ty::iface_methods(ccx.tcx, local_def(it.id)), {|m|
ty::type_has_vars(ty::mk_fn(ccx.tcx, m.fty))}) {
impl::trans_iface_vtable(ccx, item_path(ccx, it), it);
}
}
_ { }
}
}
@ -5032,9 +4996,9 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
discrims: ast_util::new_def_id_hash::<ValueRef>(),
discrim_symbols: int_hash::<str>(),
tydescs: ty::new_ty_hash(),
dicts: map::hashmap(hash_dict_id, {|a, b| a == b}),
external: util::common::new_def_hash(),
monomorphized: map::hashmap(hash_mono_id, {|a, b| a == b}),
vtables: map::hashmap(hash_mono_id, {|a, b| a == b}),
module_data: str_hash::<ValueRef>(),
lltypes: ty::new_ty_hash(),
names: new_namegen(),

View file

@ -515,26 +515,7 @@ fn trans_bind_1(cx: block, outgoing_fty: ty::t,
// Figure out which tydescs we need to pass, if any.
let (outgoing_fty_real, lltydescs, param_bounds) = alt f_res.generic {
generic_full(ginfo) {
let tds = [], orig = 0u;
vec::iter2(ginfo.tydescs, *ginfo.param_bounds) {|td, bounds|
tds += [td];
for bound in *bounds {
alt bound {
ty::bound_iface(_) {
let dict = impl::get_dict(
bcx, option::get(ginfo.origins)[orig]);
tds += [PointerCast(bcx, dict.val, val_ty(td))];
orig += 1u;
bcx = dict.bcx;
}
_ {}
}
}
}
lazily_emit_all_generic_info_tydesc_glues(ccx, ginfo);
(ginfo.item_type, tds, ginfo.param_bounds)
}
generic_full(ginfo) { fail; }
_ { (outgoing_fty, [], @[]) }
};
@ -560,9 +541,6 @@ fn trans_bind_1(cx: block, outgoing_fty: ty::t,
self_env(slf, slf_t) {
([env_copy(slf, slf_t, owned)], target_self(f_res.val))
}
dict_env(_, _) {
ccx.sess.unimpl("binding of dynamic method calls");
}
};
// Actually construct the closure

View file

@ -90,11 +90,12 @@ type crate_ctxt = {
discrims: hashmap<ast::def_id, ValueRef>,
discrim_symbols: hashmap<ast::node_id, str>,
tydescs: hashmap<ty::t, @tydesc_info>,
dicts: hashmap<dict_id, ValueRef>,
// Track mapping of external ids to local items imported for inlining
external: hashmap<ast::def_id, option<ast::node_id>>,
// Cache instances of monomorphized functions
monomorphized: hashmap<mono_id, {llfn: ValueRef, fty: ty::t}>,
// Cache generated vtables
vtables: hashmap<mono_id, ValueRef>,
module_data: hashmap<str, ValueRef>,
lltypes: hashmap<ty::t, TypeRef>,
names: namegen,
@ -846,30 +847,16 @@ pure fn type_has_static_size(cx: @crate_ctxt, t: ty::t) -> bool {
!ty::type_has_dynamic_size(cx.tcx, t)
}
// Used to identify cached dictionaries
enum dict_param {
dict_param_dict(dict_id),
dict_param_ty(ty::t),
}
type dict_id = @{def: ast::def_id, params: [dict_param]};
fn hash_dict_id(&&dp: dict_id) -> uint {
let h = syntax::ast_util::hash_def_id(dp.def);
for param in dp.params {
h = h << 2u;
alt param {
dict_param_dict(d) { h += hash_dict_id(d); }
dict_param_ty(t) { h += ty::type_id(t); }
}
}
h
}
// Used to identify cached monomorphized functions
type mono_id = @{def: ast::def_id, substs: [ty::t], dicts: [dict_id]};
enum mono_dicts { some_dicts([mono_id]), no_dicts }
type mono_id = @{def: ast::def_id, substs: [ty::t], dicts: mono_dicts};
fn hash_mono_id(&&mi: mono_id) -> uint {
let h = syntax::ast_util::hash_def_id(mi.def);
for ty in mi.substs { h = (h << 2u) + ty::type_id(ty); }
for dict in mi.dicts { h = (h << 2u) + hash_dict_id(dict); }
alt mi.dicts {
some_dicts(ds) { for d in ds { h = (h << 2u) + hash_mono_id(d); } }
_ {}
}
h
}

View file

@ -14,36 +14,6 @@ import lib::llvm::llvm::LLVMGetParam;
import ast_map::{path, path_mod, path_name};
import std::map::hashmap;
// Translation functionality related to impls and ifaces
//
// Terminology:
// vtable: a table of function pointers pointing to method wrappers
// of an impl that implements an iface
// dict: a record containing a vtable pointer along with pointers to
// all tydescs and other dicts needed to run methods in this vtable
// (i.e. corresponding to the type parameters of the impl)
// wrapper: a function that takes a dict as first argument, along
// with the method-specific tydescs for a method (and all
// other args the method expects), which fetches the extra
// tydescs and dicts from the dict, splices them into the
// arglist, and calls through to the actual method
//
// Generic functions take, along with their normal arguments, a number
// of extra tydesc and dict arguments -- one tydesc for each type
// parameter, one dict (following the tydesc in the arg order) for
// each interface bound on a type parameter.
//
// Most dicts are completely static, and are allocated and filled at
// compile time. Dicts that depend on run-time values (tydescs or
// dicts for type parameter types) are built at run-time, and interned
// through upcall_intern_dict in the runtime. This means that dict
// pointers are self-contained things that do not need to be cleaned
// up.
//
// The trans_constants pass in trans.rs outputs the vtables. Typeck
// annotates nodes with information about the methods and dicts that
// are referenced (ccx.method_map and ccx.dict_map).
fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
methods: [@ast::method], tps: [ast::ty_param]) {
if tps.len() > 0u { ret; }
@ -81,18 +51,15 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
trans_static_callee(bcx, callee_id, self, did, none)
}
typeck::method_param(iid, off, p, b) {
alt bcx.fcx.param_substs {
alt check bcx.fcx.param_substs {
some(substs) {
trans_monomorphized_callee(bcx, callee_id, self,
iid, off, p, b, substs)
}
none {
trans_param_callee(bcx, callee_id, self, iid, off, p, b)
}
}
}
typeck::method_iface(iid, off) {
trans_iface_callee(bcx, callee_id, self, iid, off)
typeck::method_iface(_, off) {
trans_iface_callee(bcx, self, callee_id, off)
}
}
}
@ -115,39 +82,20 @@ fn wrapper_fn_ty(ccx: @crate_ctxt, dict_ty: TypeRef, fty: ty::t,
}
fn trans_vtable_callee(bcx: block, env: callee_env, dict: ValueRef,
callee_id: ast::node_id, iface_id: ast::def_id,
n_method: uint) -> lval_maybe_callee {
callee_id: ast::node_id, n_method: uint)
-> lval_maybe_callee {
let bcx = bcx, ccx = bcx.ccx(), tcx = ccx.tcx;
let method = ty::iface_methods(tcx, iface_id)[n_method];
let method_ty = ty::mk_fn(tcx, method.fty);
let {ty: fty, llty: llfty} =
wrapper_fn_ty(ccx, val_ty(dict), method_ty, method.tps);
let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
let fty = node_id_type(bcx, callee_id);
let llfty = type_of::type_of_fn_from_ty(ccx, fty, []);
let vtable = PointerCast(bcx, dict,
T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
let generic = generic_none;
if (*method.tps).len() > 0u || ty::type_has_params(fty) {
let tydescs = [], tis = [];
let tptys = node_id_type_params(bcx, callee_id);
for t in vec::tailn(tptys, tptys.len() - (*method.tps).len()) {
let ti = none;
let td = get_tydesc(bcx, t, true, ti);
tis += [ti];
tydescs += [td.val];
bcx = td.bcx;
}
generic = generic_full({item_type: fty,
static_tis: tis,
tydescs: tydescs,
param_bounds: method.tps,
origins: ccx.maps.dict_map.find(callee_id)});
}
{bcx: bcx, val: mptr, kind: owned,
env: env,
generic: generic}
generic: generic_none}
}
fn method_with_name(ccx: crate_ctxt, impl_id: ast::def_id,
fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
name: ast::ident) -> ast::def_id {
if impl_id.crate == ast::local_crate {
alt check ccx.tcx.items.get(impl_id.node) {
@ -172,8 +120,8 @@ fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id,
ret trans_static_callee(bcx, callee_id, base, mth_id,
some((tys, sub_origins)));
}
typeck::dict_iface(iid) {
ret trans_iface_callee(bcx, callee_id, base, iid, n_method);
typeck::dict_iface(iid, tps) {
ret trans_iface_callee(bcx, base, callee_id, n_method);
}
typeck::dict_param(n_param, n_bound) {
fail "dict_param left in monomorphized function's dict substs";
@ -181,20 +129,9 @@ fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id,
}
}
// Method callee where the dict comes from a type param
fn trans_param_callee(bcx: block, callee_id: ast::node_id,
base: @ast::expr, iface_id: ast::def_id, n_method: uint,
n_param: uint, n_bound: uint) -> lval_maybe_callee {
let {bcx, val} = trans_self_arg(bcx, base);
let dict = option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound];
trans_vtable_callee(bcx, dict_env(dict, val), dict,
callee_id, iface_id, n_method)
}
// Method callee where the dict comes from a boxed iface
fn trans_iface_callee(bcx: block, callee_id: ast::node_id,
base: @ast::expr, iface_id: ast::def_id, n_method: uint)
fn trans_iface_callee(bcx: block, base: @ast::expr,
callee_id: ast::node_id, n_method: uint)
-> lval_maybe_callee {
let {bcx, val} = trans_temp_expr(bcx, base);
let dict = Load(bcx, PointerCast(bcx, GEPi(bcx, val, [0, 0]),
@ -202,8 +139,8 @@ fn trans_iface_callee(bcx: block, callee_id: ast::node_id,
let box = Load(bcx, GEPi(bcx, val, [0, 1]));
// FIXME[impl] I doubt this is alignment-safe
let self = GEPi(bcx, box, [0, abi::box_field_body]);
trans_vtable_callee(bcx, dict_env(dict, self), dict,
callee_id, iface_id, n_method)
trans_vtable_callee(bcx, self_env(self, expr_ty(bcx, base)), dict,
callee_id, n_method)
}
fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
@ -214,18 +151,6 @@ fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
{inputs: args, output: out_ty}
}
fn trans_vtable(ccx: @crate_ctxt, id: ast::node_id, name: str,
ptrs: [ValueRef]) {
let tbl = C_struct(ptrs);
let vt_gvar = str::as_c_str(name, {|buf|
llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf)
});
llvm::LLVMSetInitializer(vt_gvar, tbl);
llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True);
ccx.item_vals.insert(id, vt_gvar);
ccx.item_symbols.insert(id, name);
}
fn find_dict_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
-> typeck::dict_origin {
let dict_off = n_bound, i = 0u;
@ -241,150 +166,93 @@ fn find_dict_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
option::get(ps.dicts)[dict_off]
}
fn resolve_dicts_in_fn_ctxt(fcx: fn_ctxt, dicts: typeck::dict_res)
-> option<typeck::dict_res> {
let result = [];
for dict in *dicts {
result += [alt dict {
typeck::dict_static(iid, tys, sub) {
alt resolve_dicts_in_fn_ctxt(fcx, sub) {
some(sub) {
let tys = alt fcx.param_substs {
some(substs) {
vec::map(tys, {|t|
ty::substitute_type_params(fcx.ccx.tcx, substs.tys, t)
})
}
_ { tys }
};
typeck::dict_static(iid, tys, sub)
}
none { ret none; }
}
fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::dict_res)
-> typeck::dict_res {
@vec::map(*vts, {|d| resolve_vtable_in_fn_ctxt(fcx, d)})
}
fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::dict_origin)
-> typeck::dict_origin {
alt vt {
typeck::dict_static(iid, tys, sub) {
let tys = alt fcx.param_substs {
some(substs) {
vec::map(tys, {|t|
ty::substitute_type_params(fcx.ccx.tcx, substs.tys, t)
})
}
typeck::dict_param(n_param, n_bound) {
alt fcx.param_substs {
some(substs) {
find_dict_in_fn_ctxt(substs, n_param, n_bound)
}
none { ret none; }
}
_ { tys }
};
typeck::dict_static(iid, tys, resolve_vtables_in_fn_ctxt(fcx, sub))
}
typeck::dict_param(n_param, n_bound) {
alt check fcx.param_substs {
some(substs) {
find_dict_in_fn_ctxt(substs, n_param, n_bound)
}
_ { dict }
}];
}
}
_ { vt }
}
some(@result)
}
fn trans_wrapper(ccx: @crate_ctxt, pt: path, llfty: TypeRef,
fill: fn(ValueRef, block) -> block)
-> ValueRef {
let name = link::mangle_internal_name_by_path(ccx, pt);
let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfty);
let fcx = new_fn_ctxt(ccx, [], llfn, none);
let bcx = top_scope_block(fcx, none), lltop = bcx.llbb;
let bcx = fill(llfn, bcx);
build_return(bcx);
finish_fn(fcx, lltop);
ret llfn;
}
fn trans_impl_wrapper(ccx: @crate_ctxt, pt: path,
extra_tps: [ty::param_bounds], real_fn: ValueRef)
-> ValueRef {
let {inputs: real_args, output: real_ret} =
llfn_arg_tys(llvm::LLVMGetElementType(val_ty(real_fn)));
let extra_ptrs = [];
for tp in extra_tps {
extra_ptrs += [T_ptr(ccx.tydesc_type)];
for bound in *tp {
alt bound {
ty::bound_iface(_) { extra_ptrs += [T_ptr(T_dict())]; }
_ {}
}
}
fn vtable_id(origin: typeck::dict_origin) -> mono_id {
alt check origin {
typeck::dict_static(impl_id, substs, sub_dicts) {
@{def: impl_id, substs: substs,
dicts: if (*sub_dicts).len() == 0u { no_dicts }
else { some_dicts(vec::map(*sub_dicts, vtable_id)) } }
}
typeck::dict_iface(iface_id, substs) {
@{def: iface_id, substs: substs, dicts: no_dicts}
}
}
let env_ty = T_ptr(T_struct([T_ptr(T_i8())] + extra_ptrs));
let n_extra_ptrs = extra_ptrs.len();
let wrap_args = [T_ptr(T_dict())] +
vec::slice(real_args, 0u, first_tp_arg) +
vec::slice(real_args, first_tp_arg + n_extra_ptrs, real_args.len());
let llfn_ty = T_fn(wrap_args, real_ret);
trans_wrapper(ccx, pt, llfn_ty, {|llfn, bcx|
let dict = PointerCast(bcx, LLVMGetParam(llfn, 0 as c_uint), env_ty);
// retptr, self
let args = [LLVMGetParam(llfn, 1 as c_uint),
LLVMGetParam(llfn, 2 as c_uint)];
let i = 0u;
// saved tydescs/dicts
while i < n_extra_ptrs {
i += 1u;
args += [load_inbounds(bcx, dict, [0, i as int])];
}
// the rest of the parameters
let j = 3u as c_uint;
let params_total = llvm::LLVMCountParamTypes(llfn_ty);
while j < params_total {
args += [LLVMGetParam(llfn, j)];
j += 1u as c_uint;
}
Call(bcx, real_fn, args);
bcx
})
}
fn trans_impl_vtable(ccx: @crate_ctxt, pt: path,
iface_id: ast::def_id, ms: [@ast::method],
tps: [ast::ty_param], it: @ast::item) {
if tps.len() > 0u { ret; }
let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id)),
path_name("wrap")];
let extra_tps = param_bounds(ccx, tps);
let ptrs = vec::map(*ty::iface_methods(ccx.tcx, iface_id), {|im|
alt vec::find(ms, {|m| m.ident == im.ident}) {
some(m) {
trans_impl_wrapper(ccx, new_pt + [path_name(m.ident)],
extra_tps, get_item_val(ccx, m.id))
}
_ {
ccx.sess.span_bug(it.span, "no matching method \
in trans_impl_vtable");
fn get_vtable(ccx: @crate_ctxt, origin: typeck::dict_origin)
-> ValueRef {
let hash_id = vtable_id(origin);
alt ccx.vtables.find(hash_id) {
some(val) { val }
none {
alt check origin {
typeck::dict_static(id, substs, sub_dicts) {
make_impl_vtable(ccx, id, substs, sub_dicts)
}
}
}
}
}
fn make_vtable(ccx: @crate_ctxt, ptrs: [ValueRef]) -> ValueRef {
let tbl = C_struct(ptrs);
let vt_gvar = str::as_c_str(ccx.names("vtable"), {|buf|
llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf)
});
let s = link::mangle_internal_name_by_path(
ccx, new_pt + [path_name("!vtable")]);
trans_vtable(ccx, it.id, s, ptrs);
llvm::LLVMSetInitializer(vt_gvar, tbl);
llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True);
lib::llvm::SetLinkage(vt_gvar, lib::llvm::InternalLinkage);
vt_gvar
}
fn trans_iface_wrapper(ccx: @crate_ctxt, pt: path, m: ty::method,
n: uint) -> ValueRef {
let {llty: llfty, _} = wrapper_fn_ty(ccx, T_ptr(T_i8()),
ty::mk_fn(ccx.tcx, m.fty), m.tps);
trans_wrapper(ccx, pt, llfty, {|llfn, bcx|
let param = PointerCast(bcx, LLVMGetParam(llfn, 2u as c_uint),
T_ptr(T_opaque_iface(ccx)));
let dict = Load(bcx, GEPi(bcx, param, [0, 0]));
let box = Load(bcx, GEPi(bcx, param, [0, 1]));
let self = GEPi(bcx, box, [0, abi::box_field_body]);
let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
T_ptr(T_array(T_ptr(llfty), n + 1u)));
let mptr = Load(bcx, GEPi(bcx, vtable, [0, n as int]));
let args = [PointerCast(bcx, dict, T_ptr(T_i8())),
LLVMGetParam(llfn, 1u as c_uint),
PointerCast(bcx, self, T_opaque_cbox_ptr(ccx))];
let i = 3u as c_uint, total = llvm::LLVMCountParamTypes(llfty);
while i < total {
args += [LLVMGetParam(llfn, i)];
i += 1u as c_uint;
fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t],
dicts: typeck::dict_res) -> ValueRef {
let tcx = ccx.tcx;
let ifce_id = ty::ty_to_def_id(option::get(ty::impl_iface(tcx, impl_id)));
make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id), {|im|
let fty = ty::substitute_type_params(tcx, substs,
ty::mk_fn(tcx, im.fty));
if (*im.tps).len() > 0u || ty::type_has_vars(fty) {
C_null(type_of_fn_from_ty(ccx, fty, []))
} else {
let m_id = method_with_name(ccx, impl_id, im.ident);
option::get(monomorphic_fn(ccx, m_id, substs, some(dicts))).llfn
}
Call(bcx, mptr, args);
bcx
})
}))
}
fn trans_iface_vtable(ccx: @crate_ctxt, pt: path, it: @ast::item) {
/*
fn make_iface_vtable(ccx: @crate_ctxt, pt: path, it: @ast::item) {
let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id))];
let i_did = local_def(it.id), i = 0u;
let ptrs = vec::map(*ty::iface_methods(ccx.tcx, i_did), {|m|
@ -528,6 +396,7 @@ fn get_dict_ptrs(bcx: block, origin: typeck::dict_origin)
}
}
}
}*/
fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest)
-> block {
@ -541,8 +410,10 @@ fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest)
let result = get_dest_addr(dest);
Store(bcx, box, PointerCast(bcx, GEPi(bcx, result, [0, 1]),
T_ptr(val_ty(box))));
let {bcx, val: dict} = get_dict(bcx, ccx.maps.dict_map.get(id)[0]);
Store(bcx, dict, PointerCast(bcx, GEPi(bcx, result, [0, 0]),
T_ptr(val_ty(dict))));
let orig = ccx.maps.dict_map.get(id)[0];
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig);
let vtable = get_vtable(bcx.ccx(), orig);
Store(bcx, vtable, PointerCast(bcx, GEPi(bcx, result, [0, 0]),
T_ptr(val_ty(vtable))));
bcx
}

View file

@ -92,6 +92,7 @@ export region, re_named, re_caller, re_block, re_inferred;
export get, type_has_params, type_has_vars, type_has_rptrs, type_id;
export same_type;
export ty_var_id;
export ty_to_def_id;
export ty_fn_args;
export type_constr;
export kind, kind_sendable, kind_copyable, kind_noncopyable;
@ -2290,6 +2291,14 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
}
}
fn ty_to_def_id(ty: t) -> ast::def_id {
alt check get(ty).struct {
ty_iface(id, _) | ty_class(id, _) | ty_res(id, _, _) | ty_enum(id, _) {
id
}
}
}
// Enum information
type variant_info = @{args: [t], ctor_ty: t, name: str,
id: ast::def_id, disr_val: int};

View file

@ -34,7 +34,7 @@ enum dict_origin {
dict_static(ast::def_id, [ty::t], dict_res),
// Param number, bound number
dict_param(uint, uint),
dict_iface(ast::def_id),
dict_iface(ast::def_id, [ty::t]),
}
type dict_map = hashmap<ast::node_id, dict_res>;
@ -3361,8 +3361,8 @@ mod dict {
}
}
}
ty::ty_iface(did, _) if iface_id == did {
ret dict_iface(did);
ty::ty_iface(did, tps) if iface_id == did {
ret dict_iface(did, tps);
}
_ {
let found = none;