Hugely simplify iface handling
With the assumption of monomorphization
This commit is contained in:
parent
168398bb3d
commit
4511f936b1
8 changed files with 138 additions and 323 deletions
|
@ -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)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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,14 +166,15 @@ 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 {
|
||||
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) {
|
||||
alt resolve_dicts_in_fn_ctxt(fcx, sub) {
|
||||
some(sub) {
|
||||
let tys = alt fcx.param_substs {
|
||||
some(substs) {
|
||||
vec::map(tys, {|t|
|
||||
|
@ -257,134 +183,76 @@ fn resolve_dicts_in_fn_ctxt(fcx: fn_ctxt, dicts: typeck::dict_res)
|
|||
}
|
||||
_ { tys }
|
||||
};
|
||||
typeck::dict_static(iid, tys, sub)
|
||||
}
|
||||
none { ret none; }
|
||||
}
|
||||
typeck::dict_static(iid, tys, resolve_vtables_in_fn_ctxt(fcx, sub))
|
||||
}
|
||||
typeck::dict_param(n_param, n_bound) {
|
||||
alt fcx.param_substs {
|
||||
alt check fcx.param_substs {
|
||||
some(substs) {
|
||||
find_dict_in_fn_ctxt(substs, n_param, n_bound)
|
||||
}
|
||||
none { ret none; }
|
||||
}
|
||||
}
|
||||
_ { dict }
|
||||
}];
|
||||
_ { vt }
|
||||
}
|
||||
some(@result)
|
||||
}
|
||||
|
||||
fn trans_wrapper(ccx: @crate_ctxt, pt: path, llfty: TypeRef,
|
||||
fill: fn(ValueRef, block) -> block)
|
||||
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}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_vtable(ccx: @crate_ctxt, origin: typeck::dict_origin)
|
||||
-> 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;
|
||||
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 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())]; }
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 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
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue