2012-03-12 22:04:27 -05:00
|
|
|
import libc::c_uint;
|
2012-01-27 06:17:06 -06:00
|
|
|
import base::*;
|
|
|
|
import common::*;
|
2012-02-21 08:22:55 -06:00
|
|
|
import type_of::*;
|
2012-01-27 06:17:06 -06:00
|
|
|
import build::*;
|
2012-01-30 23:00:57 -06:00
|
|
|
import driver::session::session;
|
2012-03-08 05:15:02 -06:00
|
|
|
import syntax::ast;
|
|
|
|
import syntax::ast_util::local_def;
|
2012-01-05 06:57:27 -06:00
|
|
|
import metadata::csearch;
|
2012-01-07 15:44:14 -06:00
|
|
|
import back::{link, abi};
|
2012-01-06 07:22:31 -06:00
|
|
|
import lib::llvm::llvm;
|
2012-02-01 04:04:56 -06:00
|
|
|
import lib::llvm::{ValueRef, TypeRef};
|
|
|
|
import lib::llvm::llvm::LLVMGetParam;
|
2012-02-03 02:53:37 -06:00
|
|
|
import ast_map::{path, path_mod, path_name};
|
2012-03-07 18:48:57 -06:00
|
|
|
import std::map::hashmap;
|
2012-01-02 05:21:44 -06:00
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
|
2012-03-07 05:54:00 -06:00
|
|
|
methods: [@ast::method], tps: [ast::ty_param]) {
|
2012-03-08 06:30:22 -06:00
|
|
|
if tps.len() > 0u { ret; }
|
2012-02-03 02:53:37 -06:00
|
|
|
let sub_path = path + [path_name(name)];
|
2012-01-02 05:21:44 -06:00
|
|
|
for m in methods {
|
2012-03-08 06:30:22 -06:00
|
|
|
if m.tps.len() == 0u {
|
|
|
|
let llfn = get_item_val(ccx, m.id);
|
|
|
|
trans_fn(ccx, sub_path + [path_name(m.ident)], m.decl, m.body,
|
|
|
|
llfn, impl_self(ty::node_id_to_type(ccx.tcx, m.self_id)),
|
|
|
|
none, m.id, none);
|
|
|
|
}
|
2012-01-02 05:21:44 -06:00
|
|
|
}
|
|
|
|
}
|
2012-01-02 06:26:51 -06:00
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_self_arg(bcx: block, base: @ast::expr) -> result {
|
2012-02-02 05:37:17 -06:00
|
|
|
let basety = expr_ty(bcx, base);
|
2012-02-02 18:50:17 -06:00
|
|
|
let m_by_ref = ast::expl(ast::by_ref);
|
2012-02-24 19:45:16 -06:00
|
|
|
let temp_cleanups = [];
|
|
|
|
let result = trans_arg_expr(bcx, {mode: m_by_ref, ty: basety},
|
|
|
|
T_ptr(type_of_or_i8(bcx.ccx(), basety)), base,
|
|
|
|
temp_cleanups);
|
|
|
|
|
|
|
|
// by-ref self argument should not require cleanup in the case of
|
|
|
|
// other arguments failing:
|
|
|
|
assert temp_cleanups == [];
|
|
|
|
|
|
|
|
ret result;
|
2012-01-02 09:50:51 -06:00
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_method_callee(bcx: block, callee_id: ast::node_id,
|
2012-01-26 05:26:14 -06:00
|
|
|
self: @ast::expr, origin: typeck::method_origin)
|
|
|
|
-> lval_maybe_callee {
|
|
|
|
alt origin {
|
|
|
|
typeck::method_static(did) {
|
2012-02-09 04:17:11 -06:00
|
|
|
trans_static_callee(bcx, callee_id, self, did, none)
|
2012-01-26 05:26:14 -06:00
|
|
|
}
|
|
|
|
typeck::method_param(iid, off, p, b) {
|
2012-03-08 09:10:25 -06:00
|
|
|
alt check bcx.fcx.param_substs {
|
2012-02-09 04:17:11 -06:00
|
|
|
some(substs) {
|
|
|
|
trans_monomorphized_callee(bcx, callee_id, self,
|
|
|
|
iid, off, p, b, substs)
|
|
|
|
}
|
|
|
|
}
|
2012-01-26 05:26:14 -06:00
|
|
|
}
|
2012-03-08 09:10:25 -06:00
|
|
|
typeck::method_iface(_, off) {
|
|
|
|
trans_iface_callee(bcx, self, callee_id, off)
|
2012-01-26 05:26:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-07 15:44:14 -06:00
|
|
|
// Method callee where the method is statically known
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_static_callee(bcx: block, callee_id: ast::node_id,
|
2012-02-09 04:17:11 -06:00
|
|
|
base: @ast::expr, did: ast::def_id,
|
2012-03-08 09:17:59 -06:00
|
|
|
substs: option<([ty::t], typeck::vtable_res)>)
|
2012-01-26 05:26:14 -06:00
|
|
|
-> lval_maybe_callee {
|
2012-01-02 09:50:51 -06:00
|
|
|
let {bcx, val} = trans_self_arg(bcx, base);
|
2012-02-14 03:47:39 -06:00
|
|
|
{env: self_env(val, node_id_type(bcx, base.id))
|
|
|
|
with lval_static_fn(bcx, did, callee_id, substs)}
|
2012-01-02 09:50:51 -06:00
|
|
|
}
|
|
|
|
|
2012-03-08 09:17:59 -06:00
|
|
|
fn trans_vtable_callee(bcx: block, env: callee_env, vtable: ValueRef,
|
2012-03-08 09:10:25 -06:00
|
|
|
callee_id: ast::node_id, n_method: uint)
|
|
|
|
-> lval_maybe_callee {
|
2012-03-08 09:17:59 -06:00
|
|
|
let bcx = bcx, ccx = bcx.ccx();
|
2012-03-08 09:10:25 -06:00
|
|
|
let fty = node_id_type(bcx, callee_id);
|
2012-03-09 03:47:40 -06:00
|
|
|
let llfty = type_of::type_of_fn_from_ty(ccx, fty);
|
2012-03-08 09:17:59 -06:00
|
|
|
let vtable = PointerCast(bcx, vtable,
|
2012-01-12 09:57:30 -06:00
|
|
|
T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
|
2012-01-02 09:50:51 -06:00
|
|
|
let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
|
2012-03-09 04:43:46 -06:00
|
|
|
{bcx: bcx, val: mptr, kind: owned, env: env, tds: none}
|
2012-01-02 09:50:51 -06:00
|
|
|
}
|
|
|
|
|
2012-03-08 09:10:25 -06:00
|
|
|
fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
|
2012-03-08 05:15:02 -06:00
|
|
|
name: ast::ident) -> ast::def_id {
|
|
|
|
if impl_id.crate == ast::local_crate {
|
|
|
|
alt check ccx.tcx.items.get(impl_id.node) {
|
|
|
|
ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) {
|
|
|
|
local_def(option::get(vec::find(ms, {|m| m.ident == name})).id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-09 03:47:40 -06:00
|
|
|
fn method_ty_param_count(ccx: @crate_ctxt, m_id: ast::def_id) -> uint {
|
2012-03-09 01:44:53 -06:00
|
|
|
if m_id.crate == ast::local_crate {
|
|
|
|
alt check ccx.tcx.items.get(m_id.node) {
|
|
|
|
ast_map::node_method(m, _, _) { vec::len(m.tps) }
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
csearch::get_type_param_count(ccx.sess.cstore, m_id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id,
|
2012-02-09 04:17:11 -06:00
|
|
|
base: @ast::expr, iface_id: ast::def_id,
|
|
|
|
n_method: uint, n_param: uint, n_bound: uint,
|
|
|
|
substs: param_substs) -> lval_maybe_callee {
|
2012-03-08 09:17:59 -06:00
|
|
|
alt find_vtable_in_fn_ctxt(substs, n_param, n_bound) {
|
2012-03-09 01:44:53 -06:00
|
|
|
typeck::vtable_static(impl_did, impl_substs, sub_origins) {
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let mname = ty::iface_methods(ccx.tcx, iface_id)[n_method].ident;
|
2012-03-08 05:15:02 -06:00
|
|
|
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
|
2012-03-09 01:44:53 -06:00
|
|
|
let n_m_tps = method_ty_param_count(ccx, mth_id);
|
|
|
|
let node_substs = node_id_type_params(bcx, callee_id);
|
|
|
|
let ty_substs = impl_substs +
|
2012-03-09 03:47:40 -06:00
|
|
|
vec::tailn(node_substs, node_substs.len() - n_m_tps);
|
2012-03-08 05:15:02 -06:00
|
|
|
ret trans_static_callee(bcx, callee_id, base, mth_id,
|
2012-03-09 01:44:53 -06:00
|
|
|
some((ty_substs, sub_origins)));
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
2012-03-08 09:17:59 -06:00
|
|
|
typeck::vtable_iface(iid, tps) {
|
2012-03-08 09:10:25 -06:00
|
|
|
ret trans_iface_callee(bcx, base, callee_id, n_method);
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
2012-03-08 09:17:59 -06:00
|
|
|
typeck::vtable_param(n_param, n_bound) {
|
|
|
|
fail "vtable_param left in monomorphized function's vtable substs";
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-08 09:17:59 -06:00
|
|
|
// Method callee where the vtable comes from a boxed iface
|
2012-03-08 09:10:25 -06:00
|
|
|
fn trans_iface_callee(bcx: block, base: @ast::expr,
|
|
|
|
callee_id: ast::node_id, n_method: uint)
|
2012-01-07 15:44:14 -06:00
|
|
|
-> lval_maybe_callee {
|
|
|
|
let {bcx, val} = trans_temp_expr(bcx, base);
|
2012-03-08 09:17:59 -06:00
|
|
|
let vtable = Load(bcx, PointerCast(bcx, GEPi(bcx, val, [0, 0]),
|
|
|
|
T_ptr(T_ptr(T_vtable()))));
|
2012-02-10 04:32:03 -06:00
|
|
|
let box = Load(bcx, GEPi(bcx, val, [0, 1]));
|
2012-01-07 15:44:14 -06:00
|
|
|
// FIXME[impl] I doubt this is alignment-safe
|
2012-02-14 03:47:39 -06:00
|
|
|
let self = GEPi(bcx, box, [0, abi::box_field_body]);
|
2012-03-08 09:17:59 -06:00
|
|
|
trans_vtable_callee(bcx, self_env(self, expr_ty(bcx, base)), vtable,
|
2012-03-08 09:10:25 -06:00
|
|
|
callee_id, n_method)
|
2012-01-07 15:44:14 -06:00
|
|
|
}
|
|
|
|
|
2012-03-08 09:17:59 -06:00
|
|
|
fn find_vtable_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
|
|
|
|
-> typeck::vtable_origin {
|
|
|
|
let vtable_off = n_bound, i = 0u;
|
|
|
|
// Vtables are stored in a flat array, finding the right one is
|
2012-02-09 04:17:11 -06:00
|
|
|
// somewhat awkward
|
|
|
|
for bounds in *ps.bounds {
|
|
|
|
if i >= n_param { break; }
|
|
|
|
for bound in *bounds {
|
2012-03-08 09:17:59 -06:00
|
|
|
alt bound { ty::bound_iface(_) { vtable_off += 1u; } _ {} }
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
2012-03-09 01:44:53 -06:00
|
|
|
i += 1u;
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
2012-03-08 09:17:59 -06:00
|
|
|
option::get(ps.vtables)[vtable_off]
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
|
|
|
|
2012-03-08 09:17:59 -06:00
|
|
|
fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res)
|
|
|
|
-> typeck::vtable_res {
|
2012-03-08 09:10:25 -06:00
|
|
|
@vec::map(*vts, {|d| resolve_vtable_in_fn_ctxt(fcx, d)})
|
|
|
|
}
|
|
|
|
|
2012-03-08 09:17:59 -06:00
|
|
|
fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
|
|
|
|
-> typeck::vtable_origin {
|
2012-03-08 09:10:25 -06:00
|
|
|
alt vt {
|
2012-03-08 09:17:59 -06:00
|
|
|
typeck::vtable_static(iid, tys, sub) {
|
2012-03-08 09:10:25 -06:00
|
|
|
let tys = alt fcx.param_substs {
|
|
|
|
some(substs) {
|
|
|
|
vec::map(tys, {|t|
|
|
|
|
ty::substitute_type_params(fcx.ccx.tcx, substs.tys, t)
|
|
|
|
})
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
2012-03-08 09:10:25 -06:00
|
|
|
_ { tys }
|
|
|
|
};
|
2012-03-08 09:17:59 -06:00
|
|
|
typeck::vtable_static(iid, tys, resolve_vtables_in_fn_ctxt(fcx, sub))
|
2012-03-08 09:10:25 -06:00
|
|
|
}
|
2012-03-08 09:17:59 -06:00
|
|
|
typeck::vtable_param(n_param, n_bound) {
|
2012-03-08 09:10:25 -06:00
|
|
|
alt check fcx.param_substs {
|
|
|
|
some(substs) {
|
2012-03-08 09:17:59 -06:00
|
|
|
find_vtable_in_fn_ctxt(substs, n_param, n_bound)
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
2012-03-08 09:10:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ { vt }
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-08 09:17:59 -06:00
|
|
|
fn vtable_id(origin: typeck::vtable_origin) -> mono_id {
|
2012-03-08 09:10:25 -06:00
|
|
|
alt check origin {
|
2012-03-08 09:17:59 -06:00
|
|
|
typeck::vtable_static(impl_id, substs, sub_vtables) {
|
2012-03-08 09:10:25 -06:00
|
|
|
@{def: impl_id, substs: substs,
|
2012-03-08 09:17:59 -06:00
|
|
|
vtables: if (*sub_vtables).len() == 0u { no_vts }
|
|
|
|
else { some_vts(vec::map(*sub_vtables, vtable_id)) } }
|
2012-03-08 09:10:25 -06:00
|
|
|
}
|
2012-03-08 09:17:59 -06:00
|
|
|
typeck::vtable_iface(iface_id, substs) {
|
|
|
|
@{def: iface_id, substs: substs, vtables: no_vts}
|
2012-03-08 09:10:25 -06:00
|
|
|
}
|
|
|
|
}
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
|
|
|
|
2012-03-08 09:17:59 -06:00
|
|
|
fn get_vtable(ccx: @crate_ctxt, origin: typeck::vtable_origin)
|
2012-01-12 09:57:30 -06:00
|
|
|
-> ValueRef {
|
2012-03-08 09:10:25 -06:00
|
|
|
let hash_id = vtable_id(origin);
|
|
|
|
alt ccx.vtables.find(hash_id) {
|
|
|
|
some(val) { val }
|
|
|
|
none {
|
|
|
|
alt check origin {
|
2012-03-08 09:17:59 -06:00
|
|
|
typeck::vtable_static(id, substs, sub_vtables) {
|
|
|
|
make_impl_vtable(ccx, id, substs, sub_vtables)
|
2012-03-08 09:10:25 -06:00
|
|
|
}
|
2012-01-02 09:50:51 -06:00
|
|
|
}
|
2012-03-08 09:10:25 -06:00
|
|
|
}
|
2012-01-02 09:50:51 -06:00
|
|
|
}
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
2012-01-02 06:26:51 -06:00
|
|
|
|
2012-03-08 09:10:25 -06:00
|
|
|
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)
|
2012-01-12 09:57:30 -06:00
|
|
|
});
|
2012-03-08 09:10:25 -06:00
|
|
|
llvm::LLVMSetInitializer(vt_gvar, tbl);
|
|
|
|
llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True);
|
|
|
|
lib::llvm::SetLinkage(vt_gvar, lib::llvm::InternalLinkage);
|
|
|
|
vt_gvar
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
2012-01-02 06:26:51 -06:00
|
|
|
|
2012-03-08 09:10:25 -06:00
|
|
|
fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t],
|
2012-03-08 09:17:59 -06:00
|
|
|
vtables: typeck::vtable_res) -> ValueRef {
|
2012-03-08 09:10:25 -06:00
|
|
|
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) {
|
2012-03-09 03:47:40 -06:00
|
|
|
C_null(type_of_fn_from_ty(ccx, fty))
|
2012-03-08 09:10:25 -06:00
|
|
|
} else {
|
|
|
|
let m_id = method_with_name(ccx, impl_id, im.ident);
|
2012-03-09 04:43:46 -06:00
|
|
|
monomorphic_fn(ccx, m_id, substs, some(vtables)).val
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
2012-03-08 09:10:25 -06:00
|
|
|
}))
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest)
|
|
|
|
-> block {
|
2012-02-10 04:32:03 -06:00
|
|
|
if dest == ignore { ret trans_expr(bcx, val, ignore); }
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2012-02-10 04:32:03 -06:00
|
|
|
let v_ty = expr_ty(bcx, val);
|
|
|
|
let {bcx, box, body} = trans_malloc_boxed(bcx, v_ty);
|
|
|
|
add_clean_free(bcx, box, false);
|
|
|
|
bcx = trans_expr_save_in(bcx, val, body);
|
|
|
|
revoke_clean(bcx, box);
|
|
|
|
let result = get_dest_addr(dest);
|
|
|
|
Store(bcx, box, PointerCast(bcx, GEPi(bcx, result, [0, 1]),
|
|
|
|
T_ptr(val_ty(box))));
|
2012-03-08 09:17:59 -06:00
|
|
|
let orig = ccx.maps.vtable_map.get(id)[0];
|
2012-03-08 09:10:25 -06:00
|
|
|
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))));
|
2012-02-10 04:32:03 -06:00
|
|
|
bcx
|
2012-01-07 15:44:14 -06:00
|
|
|
}
|