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-01-06 10:50:55 -06:00
|
|
|
// 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
|
2012-02-10 04:32:03 -06:00
|
|
|
// annotates nodes with information about the methods and dicts that
|
2012-01-06 10:50:55 -06:00
|
|
|
// are referenced (ccx.method_map and ccx.dict_map).
|
|
|
|
|
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-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-07 05:21:08 -06:00
|
|
|
let llfn = get_item_val(ccx, m.id);
|
|
|
|
let m_bounds = param_bounds(ccx, tps + m.tps);
|
|
|
|
trans_fn(ccx, sub_path + [path_name(m.ident)], m.decl, m.body,
|
2012-03-07 05:54:00 -06:00
|
|
|
llfn, impl_self(ty::node_id_to_type(ccx.tcx, m.self_id)),
|
2012-03-07 05:21:08 -06:00
|
|
|
m_bounds, 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-02-09 04:17:11 -06:00
|
|
|
alt 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)
|
|
|
|
}
|
|
|
|
}
|
2012-01-26 05:26:14 -06:00
|
|
|
}
|
2012-02-13 11:56:09 -06:00
|
|
|
typeck::method_iface(iid, off) {
|
|
|
|
trans_iface_callee(bcx, callee_id, self, iid, 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,
|
|
|
|
substs: option<([ty::t], typeck::dict_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-14 19:31:16 -05:00
|
|
|
fn wrapper_fn_ty(ccx: @crate_ctxt, dict_ty: TypeRef, fty: ty::t,
|
2012-01-30 04:52:34 -06:00
|
|
|
tps: @[ty::param_bounds]) -> {ty: ty::t, llty: TypeRef} {
|
|
|
|
let bare_fn_ty = type_of_fn_from_ty(ccx, fty, *tps);
|
2012-01-12 09:57:30 -06:00
|
|
|
let {inputs, output} = llfn_arg_tys(bare_fn_ty);
|
|
|
|
{ty: fty, llty: T_fn([dict_ty] + inputs, output)}
|
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_vtable_callee(bcx: block, env: callee_env, dict: ValueRef,
|
2012-01-26 05:26:14 -06:00
|
|
|
callee_id: ast::node_id, iface_id: ast::def_id,
|
2012-01-07 15:44:14 -06:00
|
|
|
n_method: uint) -> lval_maybe_callee {
|
2012-02-21 07:20:18 -06:00
|
|
|
let bcx = bcx, ccx = bcx.ccx(), tcx = ccx.tcx;
|
2012-01-04 04:32:26 -06:00
|
|
|
let method = ty::iface_methods(tcx, iface_id)[n_method];
|
2012-02-29 13:35:44 -06:00
|
|
|
let method_ty = ty::mk_fn(tcx, method.fty);
|
2012-01-30 04:52:34 -06:00
|
|
|
let {ty: fty, llty: llfty} =
|
2012-02-29 13:35:44 -06:00
|
|
|
wrapper_fn_ty(ccx, val_ty(dict), method_ty, method.tps);
|
2012-01-02 09:50:51 -06:00
|
|
|
let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
|
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-02-07 04:25:04 -06:00
|
|
|
let generic = generic_none;
|
2012-02-14 02:10:47 -06:00
|
|
|
if (*method.tps).len() > 0u || ty::type_has_params(fty) {
|
2012-01-04 04:32:26 -06:00
|
|
|
let tydescs = [], tis = [];
|
2012-02-09 07:33:00 -06:00
|
|
|
let tptys = node_id_type_params(bcx, callee_id);
|
2012-03-10 02:44:13 -06:00
|
|
|
for t in vec::tailn(tptys, tptys.len() - (*method.tps).len()) {
|
2012-01-04 04:32:26 -06:00
|
|
|
let ti = none;
|
2012-02-17 08:45:38 -06:00
|
|
|
let td = get_tydesc(bcx, t, true, ti);
|
2012-01-04 04:32:26 -06:00
|
|
|
tis += [ti];
|
|
|
|
tydescs += [td.val];
|
|
|
|
bcx = td.bcx;
|
|
|
|
}
|
2012-02-07 04:25:04 -06:00
|
|
|
generic = generic_full({item_type: fty,
|
|
|
|
static_tis: tis,
|
|
|
|
tydescs: tydescs,
|
|
|
|
param_bounds: method.tps,
|
2012-02-14 17:21:53 -06:00
|
|
|
origins: ccx.maps.dict_map.find(callee_id)});
|
2012-01-04 04:32:26 -06:00
|
|
|
}
|
2012-01-02 09:50:51 -06:00
|
|
|
{bcx: bcx, val: mptr, kind: owned,
|
2012-02-14 03:47:39 -06:00
|
|
|
env: env,
|
2012-01-04 04:32:26 -06:00
|
|
|
generic: generic}
|
2012-01-02 09:50:51 -06:00
|
|
|
}
|
|
|
|
|
2012-03-08 05:15:02 -06:00
|
|
|
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) {
|
|
|
|
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-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 {
|
|
|
|
alt find_dict_in_fn_ctxt(substs, n_param, n_bound) {
|
|
|
|
typeck::dict_static(impl_did, tys, sub_origins) {
|
2012-02-21 07:20:18 -06:00
|
|
|
let tcx = bcx.tcx();
|
2012-02-09 04:17:11 -06:00
|
|
|
let mname = ty::iface_methods(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);
|
|
|
|
ret trans_static_callee(bcx, callee_id, base, mth_id,
|
2012-02-09 04:17:11 -06:00
|
|
|
some((tys, sub_origins)));
|
|
|
|
}
|
2012-02-13 11:56:09 -06:00
|
|
|
typeck::dict_iface(iid) {
|
|
|
|
ret trans_iface_callee(bcx, callee_id, base, iid, n_method);
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
|
|
|
typeck::dict_param(n_param, n_bound) {
|
|
|
|
fail "dict_param left in monomorphized function's dict substs";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-07 15:44:14 -06:00
|
|
|
// Method callee where the dict comes from a type param
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_param_callee(bcx: block, callee_id: ast::node_id,
|
2012-01-07 15:44:14 -06:00
|
|
|
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];
|
2012-02-14 03:47:39 -06:00
|
|
|
trans_vtable_callee(bcx, dict_env(dict, val), dict,
|
|
|
|
callee_id, iface_id, n_method)
|
2012-01-07 15:44:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method callee where the dict comes from a boxed iface
|
2012-02-17 06:17:40 -06:00
|
|
|
fn trans_iface_callee(bcx: block, callee_id: ast::node_id,
|
2012-02-13 11:56:09 -06:00
|
|
|
base: @ast::expr, iface_id: ast::def_id, n_method: uint)
|
2012-01-07 15:44:14 -06:00
|
|
|
-> lval_maybe_callee {
|
|
|
|
let {bcx, val} = trans_temp_expr(bcx, base);
|
2012-02-10 04:32:03 -06:00
|
|
|
let dict = Load(bcx, PointerCast(bcx, GEPi(bcx, val, [0, 0]),
|
2012-01-07 15:44:14 -06:00
|
|
|
T_ptr(T_ptr(T_dict()))));
|
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]);
|
|
|
|
trans_vtable_callee(bcx, dict_env(dict, self), dict,
|
|
|
|
callee_id, iface_id, n_method)
|
2012-01-07 15:44:14 -06:00
|
|
|
}
|
|
|
|
|
2012-01-02 06:26:51 -06:00
|
|
|
fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
|
2012-01-06 07:22:31 -06:00
|
|
|
let out_ty = llvm::LLVMGetReturnType(ft);
|
|
|
|
let n_args = llvm::LLVMCountParamTypes(ft);
|
2012-03-12 17:52:30 -05:00
|
|
|
let args = vec::from_elem(n_args as uint, 0 as TypeRef);
|
2012-02-28 22:43:39 -06:00
|
|
|
unsafe { llvm::LLVMGetParamTypes(ft, vec::unsafe::to_ptr(args)); }
|
2012-01-02 06:26:51 -06:00
|
|
|
{inputs: args, output: out_ty}
|
|
|
|
}
|
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn trans_vtable(ccx: @crate_ctxt, id: ast::node_id, name: str,
|
2012-01-12 09:57:30 -06:00
|
|
|
ptrs: [ValueRef]) {
|
|
|
|
let tbl = C_struct(ptrs);
|
2012-03-14 17:10:34 -05:00
|
|
|
let vt_gvar = str::as_c_str(name, {|buf|
|
2012-01-12 09:57:30 -06:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf)
|
|
|
|
});
|
|
|
|
llvm::LLVMSetInitializer(vt_gvar, tbl);
|
|
|
|
llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True);
|
2012-03-07 05:21:08 -06:00
|
|
|
ccx.item_vals.insert(id, vt_gvar);
|
2012-01-12 09:57:30 -06:00
|
|
|
ccx.item_symbols.insert(id, name);
|
|
|
|
}
|
|
|
|
|
2012-02-09 04:17:11 -06:00
|
|
|
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;
|
|
|
|
// Dicts are stored in a flat array, finding the right one is
|
|
|
|
// somewhat awkward
|
|
|
|
for bounds in *ps.bounds {
|
|
|
|
i += 1u;
|
|
|
|
if i >= n_param { break; }
|
|
|
|
for bound in *bounds {
|
|
|
|
alt bound { ty::bound_iface(_) { dict_off += 1u; } _ {} }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
option::get(ps.dicts)[dict_off]
|
|
|
|
}
|
|
|
|
|
2012-02-21 08:11:20 -06:00
|
|
|
fn resolve_dicts_in_fn_ctxt(fcx: fn_ctxt, dicts: typeck::dict_res)
|
2012-02-09 04:17:11 -06:00
|
|
|
-> 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) {
|
2012-02-09 07:33:00 -06:00
|
|
|
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)
|
|
|
|
}
|
2012-02-09 04:17:11 -06:00
|
|
|
none { ret none; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ { dict }
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
some(@result)
|
|
|
|
}
|
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn trans_wrapper(ccx: @crate_ctxt, pt: path, llfty: TypeRef,
|
2012-02-17 06:17:40 -06:00
|
|
|
fill: fn(ValueRef, block) -> block)
|
2012-01-12 09:57:30 -06:00
|
|
|
-> ValueRef {
|
|
|
|
let name = link::mangle_internal_name_by_path(ccx, pt);
|
|
|
|
let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfty);
|
2012-02-03 02:53:37 -06:00
|
|
|
let fcx = new_fn_ctxt(ccx, [], llfn, none);
|
2012-02-17 06:17:40 -06:00
|
|
|
let bcx = top_scope_block(fcx, none), lltop = bcx.llbb;
|
2012-01-12 09:57:30 -06:00
|
|
|
let bcx = fill(llfn, bcx);
|
|
|
|
build_return(bcx);
|
|
|
|
finish_fn(fcx, lltop);
|
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn trans_impl_wrapper(ccx: @crate_ctxt, pt: path,
|
2012-01-12 09:57:30 -06:00
|
|
|
extra_tps: [ty::param_bounds], real_fn: ValueRef)
|
|
|
|
-> ValueRef {
|
2012-01-02 06:26:51 -06:00
|
|
|
let {inputs: real_args, output: real_ret} =
|
2012-01-06 07:22:31 -06:00
|
|
|
llfn_arg_tys(llvm::LLVMGetElementType(val_ty(real_fn)));
|
2012-01-02 09:50:51 -06:00
|
|
|
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));
|
2012-02-14 02:10:47 -06:00
|
|
|
let n_extra_ptrs = extra_ptrs.len();
|
2012-01-02 09:50:51 -06:00
|
|
|
|
2012-02-21 07:20:18 -06:00
|
|
|
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());
|
2012-01-02 06:26:51 -06:00
|
|
|
let llfn_ty = T_fn(wrap_args, real_ret);
|
2012-01-12 09:57:30 -06:00
|
|
|
trans_wrapper(ccx, pt, llfn_ty, {|llfn, bcx|
|
2012-01-18 05:29:37 -06:00
|
|
|
let dict = PointerCast(bcx, LLVMGetParam(llfn, 0 as c_uint), env_ty);
|
2012-01-12 09:57:30 -06:00
|
|
|
// retptr, self
|
2012-01-18 05:29:37 -06:00
|
|
|
let args = [LLVMGetParam(llfn, 1 as c_uint),
|
|
|
|
LLVMGetParam(llfn, 2 as c_uint)];
|
2012-01-16 04:21:01 -06:00
|
|
|
let i = 0u;
|
2012-01-12 09:57:30 -06:00
|
|
|
// saved tydescs/dicts
|
|
|
|
while i < n_extra_ptrs {
|
|
|
|
i += 1u;
|
|
|
|
args += [load_inbounds(bcx, dict, [0, i as int])];
|
|
|
|
}
|
|
|
|
// the rest of the parameters
|
2012-01-18 05:29:37 -06:00
|
|
|
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;
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
|
|
|
Call(bcx, real_fn, args);
|
|
|
|
bcx
|
|
|
|
})
|
|
|
|
}
|
2012-01-02 06:26:51 -06:00
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn trans_impl_vtable(ccx: @crate_ctxt, pt: path,
|
2012-01-12 09:57:30 -06:00
|
|
|
iface_id: ast::def_id, ms: [@ast::method],
|
|
|
|
tps: [ast::ty_param], it: @ast::item) {
|
2012-02-03 02:53:37 -06:00
|
|
|
let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id)),
|
|
|
|
path_name("wrap")];
|
2012-03-01 21:37:52 -06:00
|
|
|
let extra_tps = param_bounds(ccx, tps);
|
2012-01-12 09:57:30 -06:00
|
|
|
let ptrs = vec::map(*ty::iface_methods(ccx.tcx, iface_id), {|im|
|
|
|
|
alt vec::find(ms, {|m| m.ident == im.ident}) {
|
|
|
|
some(m) {
|
2012-03-01 21:37:52 -06:00
|
|
|
trans_impl_wrapper(ccx, new_pt + [path_name(m.ident)],
|
2012-03-07 05:21:08 -06:00
|
|
|
extra_tps, get_item_val(ccx, m.id))
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
_ {
|
2012-03-05 18:27:27 -06:00
|
|
|
ccx.sess.span_bug(it.span, "no matching method \
|
2012-03-07 05:21:08 -06:00
|
|
|
in trans_impl_vtable");
|
2012-01-30 23:00:57 -06:00
|
|
|
}
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
|
|
|
});
|
2012-02-03 02:53:37 -06:00
|
|
|
let s = link::mangle_internal_name_by_path(
|
|
|
|
ccx, new_pt + [path_name("!vtable")]);
|
2012-01-12 09:57:30 -06:00
|
|
|
trans_vtable(ccx, it.id, s, ptrs);
|
|
|
|
}
|
2012-01-02 06:26:51 -06:00
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn trans_iface_wrapper(ccx: @crate_ctxt, pt: path, m: ty::method,
|
2012-01-12 09:57:30 -06:00
|
|
|
n: uint) -> ValueRef {
|
2012-01-30 04:52:34 -06:00
|
|
|
let {llty: llfty, _} = wrapper_fn_ty(ccx, T_ptr(T_i8()),
|
|
|
|
ty::mk_fn(ccx.tcx, m.fty), m.tps);
|
2012-01-12 09:57:30 -06:00
|
|
|
trans_wrapper(ccx, pt, llfty, {|llfn, bcx|
|
2012-02-10 04:32:03 -06:00
|
|
|
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]);
|
2012-01-12 09:57:30 -06:00
|
|
|
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())),
|
2012-01-18 05:29:37 -06:00
|
|
|
LLVMGetParam(llfn, 1u as c_uint),
|
2012-02-10 04:32:03 -06:00
|
|
|
PointerCast(bcx, self, T_opaque_cbox_ptr(ccx))];
|
2012-01-18 05:29:37 -06:00
|
|
|
let i = 3u as c_uint, total = llvm::LLVMCountParamTypes(llfty);
|
2012-01-12 09:57:30 -06:00
|
|
|
while i < total {
|
|
|
|
args += [LLVMGetParam(llfn, i)];
|
2012-01-18 05:29:37 -06:00
|
|
|
i += 1u as c_uint;
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
|
|
|
Call(bcx, mptr, args);
|
|
|
|
bcx
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2012-03-14 19:31:16 -05:00
|
|
|
fn trans_iface_vtable(ccx: @crate_ctxt, pt: path, it: @ast::item) {
|
2012-02-03 02:53:37 -06:00
|
|
|
let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id))];
|
2012-03-08 05:15:02 -06:00
|
|
|
let i_did = local_def(it.id), i = 0u;
|
2012-01-12 09:57:30 -06:00
|
|
|
let ptrs = vec::map(*ty::iface_methods(ccx.tcx, i_did), {|m|
|
2012-02-03 02:53:37 -06:00
|
|
|
let w = trans_iface_wrapper(ccx, new_pt + [path_name(m.ident)], m, i);
|
2012-01-02 06:26:51 -06:00
|
|
|
i += 1u;
|
2012-01-12 09:57:30 -06:00
|
|
|
w
|
|
|
|
});
|
2012-02-03 02:53:37 -06:00
|
|
|
let s = link::mangle_internal_name_by_path(
|
|
|
|
ccx, new_pt + [path_name("!vtable")]);
|
2012-01-12 09:57:30 -06:00
|
|
|
trans_vtable(ccx, it.id, s, ptrs);
|
2012-01-02 06:26:51 -06:00
|
|
|
}
|
|
|
|
|
2012-01-06 07:22:31 -06:00
|
|
|
fn dict_is_static(tcx: ty::ctxt, origin: typeck::dict_origin) -> bool {
|
|
|
|
alt origin {
|
|
|
|
typeck::dict_static(_, ts, origs) {
|
2012-02-03 08:15:28 -06:00
|
|
|
vec::all(ts, {|t| !ty::type_has_params(t)}) &&
|
2012-01-06 07:22:31 -06:00
|
|
|
vec::all(*origs, {|o| dict_is_static(tcx, o)})
|
|
|
|
}
|
2012-01-12 09:57:30 -06:00
|
|
|
typeck::dict_iface(_) { true }
|
|
|
|
_ { false }
|
2012-01-06 07:22:31 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn get_dict(bcx: block, origin: typeck::dict_origin) -> result {
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2012-01-06 07:22:31 -06:00
|
|
|
alt origin {
|
|
|
|
typeck::dict_static(impl_did, tys, sub_origins) {
|
2012-01-06 10:29:06 -06:00
|
|
|
if dict_is_static(ccx.tcx, origin) {
|
2012-01-06 07:22:31 -06:00
|
|
|
ret rslt(bcx, get_static_dict(bcx, origin));
|
|
|
|
}
|
|
|
|
let {bcx, ptrs} = get_dict_ptrs(bcx, origin);
|
2012-02-14 02:10:47 -06:00
|
|
|
let pty = T_ptr(T_i8()), dict_ty = T_array(pty, ptrs.len());
|
2012-01-06 07:22:31 -06:00
|
|
|
let dict = alloca(bcx, dict_ty), i = 0;
|
|
|
|
for ptr in ptrs {
|
|
|
|
Store(bcx, PointerCast(bcx, ptr, pty), GEPi(bcx, dict, [0, i]));
|
|
|
|
i += 1;
|
|
|
|
}
|
2012-01-06 10:29:06 -06:00
|
|
|
dict = Call(bcx, ccx.upcalls.intern_dict,
|
2012-02-14 02:10:47 -06:00
|
|
|
[C_uint(ccx, ptrs.len()),
|
2012-01-06 10:29:06 -06:00
|
|
|
PointerCast(bcx, dict, T_ptr(T_dict()))]);
|
|
|
|
rslt(bcx, dict)
|
2012-01-06 07:22:31 -06:00
|
|
|
}
|
|
|
|
typeck::dict_param(n_param, n_bound) {
|
|
|
|
rslt(bcx, option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound])
|
|
|
|
}
|
2012-01-12 09:57:30 -06:00
|
|
|
typeck::dict_iface(did) {
|
|
|
|
ret rslt(bcx, get_static_dict(bcx, origin));
|
|
|
|
}
|
2012-01-06 07:22:31 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dict_id(tcx: ty::ctxt, origin: typeck::dict_origin) -> dict_id {
|
|
|
|
alt origin {
|
|
|
|
typeck::dict_static(did, ts, origs) {
|
|
|
|
let d_params = [], orig = 0u;
|
2012-02-14 02:10:47 -06:00
|
|
|
if ts.len() == 0u { ret @{def: did, params: d_params}; }
|
2012-01-06 07:22:31 -06:00
|
|
|
let impl_params = ty::lookup_item_type(tcx, did).bounds;
|
|
|
|
vec::iter2(ts, *impl_params) {|t, bounds|
|
|
|
|
d_params += [dict_param_ty(t)];
|
|
|
|
for bound in *bounds {
|
|
|
|
alt bound {
|
|
|
|
ty::bound_iface(_) {
|
|
|
|
d_params += [dict_param_dict(dict_id(tcx, origs[orig]))];
|
|
|
|
orig += 1u;
|
|
|
|
}
|
2012-01-30 04:52:34 -06:00
|
|
|
_ {}
|
2012-01-06 07:22:31 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-12 09:57:30 -06:00
|
|
|
@{def: did, params: d_params}
|
|
|
|
}
|
|
|
|
typeck::dict_iface(did) {
|
|
|
|
@{def: did, params: []}
|
2012-01-06 07:22:31 -06:00
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
_ {
|
2012-03-05 18:27:27 -06:00
|
|
|
tcx.sess.bug("unexpected dict_param in dict_id");
|
2012-01-30 23:00:57 -06:00
|
|
|
}
|
2012-01-06 07:22:31 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn get_static_dict(bcx: block, origin: typeck::dict_origin)
|
2012-01-06 07:22:31 -06:00
|
|
|
-> ValueRef {
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2012-01-06 07:22:31 -06:00
|
|
|
let id = dict_id(ccx.tcx, origin);
|
|
|
|
alt ccx.dicts.find(id) {
|
|
|
|
some(d) { ret d; }
|
2012-01-19 00:37:22 -06:00
|
|
|
none {}
|
2012-01-06 07:22:31 -06:00
|
|
|
}
|
|
|
|
let ptrs = C_struct(get_dict_ptrs(bcx, origin).ptrs);
|
2012-01-13 02:32:05 -06:00
|
|
|
let name = ccx.names("dict");
|
2012-03-14 17:10:34 -05:00
|
|
|
let gvar = str::as_c_str(name, {|buf|
|
2012-01-06 07:22:31 -06:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, val_ty(ptrs), buf)
|
|
|
|
});
|
|
|
|
llvm::LLVMSetGlobalConstant(gvar, lib::llvm::True);
|
|
|
|
llvm::LLVMSetInitializer(gvar, ptrs);
|
2012-02-01 04:04:56 -06:00
|
|
|
lib::llvm::SetLinkage(gvar, lib::llvm::InternalLinkage);
|
2012-01-06 07:22:31 -06:00
|
|
|
let cast = llvm::LLVMConstPointerCast(gvar, T_ptr(T_dict()));
|
|
|
|
ccx.dicts.insert(id, cast);
|
|
|
|
cast
|
|
|
|
}
|
|
|
|
|
2012-02-17 06:17:40 -06:00
|
|
|
fn get_dict_ptrs(bcx: block, origin: typeck::dict_origin)
|
|
|
|
-> {bcx: block, ptrs: [ValueRef]} {
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2012-03-14 19:31:16 -05:00
|
|
|
fn get_vtable(ccx: @crate_ctxt, did: ast::def_id) -> ValueRef {
|
2012-01-12 09:57:30 -06:00
|
|
|
if did.crate == ast::local_crate {
|
2012-03-07 05:21:08 -06:00
|
|
|
get_item_val(ccx, did.node)
|
2012-01-05 06:57:27 -06:00
|
|
|
} else {
|
2012-01-12 10:59:49 -06:00
|
|
|
let name = csearch::get_symbol(ccx.sess.cstore, did);
|
2012-01-05 06:57:27 -06:00
|
|
|
get_extern_const(ccx.externs, ccx.llmod, name, T_ptr(T_i8()))
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
alt origin {
|
|
|
|
typeck::dict_static(impl_did, tys, sub_origins) {
|
2012-01-02 09:50:51 -06:00
|
|
|
let impl_params = ty::lookup_item_type(ccx.tcx, impl_did).bounds;
|
2012-01-12 09:57:30 -06:00
|
|
|
let ptrs = [get_vtable(ccx, impl_did)];
|
2012-02-17 08:45:38 -06:00
|
|
|
let origin = 0u, bcx = bcx;
|
2012-01-06 07:22:31 -06:00
|
|
|
vec::iter2(*impl_params, tys) {|param, ty|
|
2012-02-17 08:45:38 -06:00
|
|
|
let rslt = get_tydesc_simple(bcx, ty, true);
|
2012-01-02 09:50:51 -06:00
|
|
|
ptrs += [rslt.val];
|
|
|
|
bcx = rslt.bcx;
|
|
|
|
for bound in *param {
|
|
|
|
alt bound {
|
|
|
|
ty::bound_iface(_) {
|
|
|
|
let res = get_dict(bcx, sub_origins[origin]);
|
|
|
|
ptrs += [res.val];
|
|
|
|
bcx = res.bcx;
|
|
|
|
origin += 1u;
|
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-06 07:22:31 -06:00
|
|
|
{bcx: bcx, ptrs: ptrs}
|
2012-01-03 09:37:41 -06:00
|
|
|
}
|
2012-01-12 09:57:30 -06:00
|
|
|
typeck::dict_iface(did) {
|
|
|
|
{bcx: bcx, ptrs: [get_vtable(ccx, did)]}
|
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
_ {
|
2012-03-05 18:27:27 -06:00
|
|
|
bcx.tcx().sess.bug("unexpected dict_param in get_dict_ptrs");
|
2012-01-30 23:00:57 -06:00
|
|
|
}
|
2012-01-02 09:50:51 -06:00
|
|
|
}
|
2012-01-06 07:22:31 -06:00
|
|
|
}
|
2012-01-07 15:44:14 -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-02-14 17:21:53 -06:00
|
|
|
let {bcx, val: dict} = get_dict(bcx, ccx.maps.dict_map.get(id)[0]);
|
2012-02-10 04:32:03 -06:00
|
|
|
Store(bcx, dict, PointerCast(bcx, GEPi(bcx, result, [0, 0]),
|
|
|
|
T_ptr(val_ty(dict))));
|
|
|
|
bcx
|
2012-01-07 15:44:14 -06:00
|
|
|
}
|