2 import trans_common::*;
4 import option::{some, none};
5 import syntax::{ast, ast_util};
6 import metadata::csearch;
8 import lib::llvm::llvm;
9 import llvm::{ValueRef, TypeRef, LLVMGetParam};
11 fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
12 id: ast::node_id, tps: [ast::ty_param]) {
13 let sub_cx = extend_path(cx, name);
15 alt cx.ccx.item_ids.find(m.id) {
17 trans_fn(extend_path(sub_cx, m.ident), m.span, m.decl, m.body,
18 llfn, impl_self(ty::node_id_to_monotype(cx.ccx.tcx, id)),
25 fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result {
27 let basety = ty::expr_ty(bcx_tcx(bcx), base);
28 let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
29 T_ptr(type_of_or_i8(bcx, basety)), tz,
31 rslt(bcx, PointerCast(bcx, val, T_opaque_boxed_closure_ptr(bcx_ccx(bcx))))
34 fn trans_static_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
35 did: ast::def_id) -> lval_maybe_callee {
36 let {bcx, val} = trans_self_arg(bcx, base);
37 {env: obj_env(val) with lval_static_fn(bcx, did, e.id)}
40 fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
41 iface_id: ast::def_id, n_method: uint,
42 n_param: uint, n_bound: uint) -> lval_maybe_callee {
43 let tcx = bcx_tcx(bcx);
44 let {bcx, val} = trans_self_arg(bcx, base);
45 let dict = option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound];
46 let method = ty::iface_methods(tcx, iface_id)[n_method];
47 let fty = ty::expr_ty(tcx, e);
48 let bare_fn_ty = type_of_fn_from_ty(bcx_ccx(bcx), ast_util::dummy_sp(),
50 let {inputs: bare_inputs, output} = llfn_arg_tys(bare_fn_ty);
51 let fn_ty = T_fn([val_ty(dict)] + bare_inputs, output);
52 let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
53 T_ptr(T_array(T_ptr(fn_ty), n_method + 1u)));
54 let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
56 if vec::len(*method.tps) > 0u {
57 let tydescs = [], tis = [];
58 let tptys = ty::node_id_to_type_params(tcx, e.id);
59 for t in vec::tail_n(tptys, vec::len(tptys) - vec::len(*method.tps)) {
60 // TODO: Doesn't always escape.
62 let td = get_tydesc(bcx, t, true, tps_normal, ti).result;
67 generic = some({item_type: fty,
70 param_bounds: method.tps,
71 origins: bcx_ccx(bcx).dict_map.find(e.id)});
73 {bcx: bcx, val: mptr, kind: owned,
74 env: dict_env(dict, val),
78 fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
79 let out_ty = llvm::LLVMGetReturnType(ft);
80 let n_args = llvm::LLVMCountParamTypes(ft);
81 let args = vec::init_elt(0 as TypeRef, n_args);
82 unsafe { llvm::LLVMGetParamTypes(ft, vec::to_ptr(args)); }
83 {inputs: args, output: out_ty}
86 fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
87 extra_tps: [ty::param_bounds], m: @ast::method) -> ValueRef {
88 let real_fn = ccx.item_ids.get(m.id);
89 let {inputs: real_args, output: real_ret} =
90 llfn_arg_tys(llvm::LLVMGetElementType(val_ty(real_fn)));
93 extra_ptrs += [T_ptr(ccx.tydesc_type)];
96 ty::bound_iface(_) { extra_ptrs += [T_ptr(T_dict())]; }
101 let env_ty = T_ptr(T_struct([T_ptr(T_i8())] + extra_ptrs));
102 let n_extra_ptrs = vec::len(extra_ptrs);
104 let wrap_args = [T_ptr(T_dict())] + vec::slice(real_args, 0u, 2u) +
105 vec::slice(real_args, 2u + vec::len(extra_ptrs), vec::len(real_args));
106 let llfn_ty = T_fn(wrap_args, real_ret);
108 let lcx = @{path: pt + ["wrapper", m.ident], module_path: [],
109 obj_typarams: [], obj_fields: [], ccx: ccx};
110 let name = link::mangle_internal_name_by_path_and_seq(ccx, pt, m.ident);
111 let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfn_ty);
112 let fcx = new_fn_ctxt(lcx, ast_util::dummy_sp(), llfn);
113 let bcx = new_top_block_ctxt(fcx), lltop = bcx.llbb;
115 let dict = PointerCast(bcx, LLVMGetParam(llfn, 0u), env_ty);
117 let args = [LLVMGetParam(llfn, 1u), LLVMGetParam(llfn, 2u)], i = 0u;
118 // saved tydescs/dicts
119 while i < n_extra_ptrs {
121 args += [load_inbounds(bcx, dict, [0, i as int])];
123 // the rest of the parameters
124 let i = 3u, params_total = llvm::LLVMCountParamTypes(llfn_ty);
125 while i < params_total {
126 args += [LLVMGetParam(llfn, i)];
129 Call(bcx, ccx.item_ids.get(m.id), args);
131 finish_fn(fcx, lltop);
135 fn dict_is_static(tcx: ty::ctxt, origin: typeck::dict_origin) -> bool {
137 typeck::dict_static(_, ts, origs) {
138 vec::all(ts, {|t| !ty::type_contains_params(tcx, t)}) &&
139 vec::all(*origs, {|o| dict_is_static(tcx, o)})
141 typeck::dict_param(_, _) { false }
145 fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
146 let ccx = bcx_ccx(bcx);
148 typeck::dict_static(impl_did, tys, sub_origins) {
149 if dict_is_static(ccx.tcx, origin) {
150 ret rslt(bcx, get_static_dict(bcx, origin));
152 let {bcx, ptrs} = get_dict_ptrs(bcx, origin);
153 let pty = T_ptr(T_i8()), dict_ty = T_array(pty, vec::len(ptrs));
154 let dict = alloca(bcx, dict_ty), i = 0;
156 Store(bcx, PointerCast(bcx, ptr, pty), GEPi(bcx, dict, [0, i]));
159 dict = Call(bcx, ccx.upcalls.intern_dict,
160 [C_uint(ccx, vec::len(ptrs)),
161 PointerCast(bcx, dict, T_ptr(T_dict()))]);
164 typeck::dict_param(n_param, n_bound) {
165 rslt(bcx, option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound])
170 fn dict_id(tcx: ty::ctxt, origin: typeck::dict_origin) -> dict_id {
172 typeck::dict_static(did, ts, origs) {
173 let d_params = [], orig = 0u;
174 if vec::len(ts) == 0u { ret @{impl_def: did, params: d_params}; }
175 let impl_params = ty::lookup_item_type(tcx, did).bounds;
176 vec::iter2(ts, *impl_params) {|t, bounds|
177 d_params += [dict_param_ty(t)];
178 for bound in *bounds {
181 d_params += [dict_param_dict(dict_id(tcx, origs[orig]))];
187 @{impl_def: did, params: d_params}
192 fn get_static_dict(bcx: @block_ctxt, origin: typeck::dict_origin)
194 let ccx = bcx_ccx(bcx);
195 let id = dict_id(ccx.tcx, origin);
196 alt ccx.dicts.find(id) {
200 let ptrs = C_struct(get_dict_ptrs(bcx, origin).ptrs);
201 let name = ccx.names.next("dict");
202 let gvar = str::as_buf(name, {|buf|
203 llvm::LLVMAddGlobal(ccx.llmod, val_ty(ptrs), buf)
205 llvm::LLVMSetGlobalConstant(gvar, lib::llvm::True);
206 llvm::LLVMSetInitializer(gvar, ptrs);
207 llvm::LLVMSetLinkage(gvar,
208 lib::llvm::LLVMInternalLinkage as llvm::Linkage);
209 let cast = llvm::LLVMConstPointerCast(gvar, T_ptr(T_dict()));
210 ccx.dicts.insert(id, cast);
214 fn get_dict_ptrs(bcx: @block_ctxt, origin: typeck::dict_origin)
215 -> {bcx: @block_ctxt, ptrs: [ValueRef]} {
216 let ccx = bcx_ccx(bcx);
218 typeck::dict_static(impl_did, tys, sub_origins) {
219 let vtable = if impl_did.crate == ast::local_crate {
220 ccx.item_ids.get(impl_did.node)
222 let name = csearch::get_symbol(ccx.sess.get_cstore(), impl_did);
223 get_extern_const(ccx.externs, ccx.llmod, name, T_ptr(T_i8()))
225 let impl_params = ty::lookup_item_type(ccx.tcx, impl_did).bounds;
226 let ptrs = [vtable], origin = 0u, ti = none, bcx = bcx;
227 vec::iter2(*impl_params, tys) {|param, ty|
228 let rslt = get_tydesc(bcx, ty, true, tps_normal, ti).result;
231 for bound in *param {
234 let res = get_dict(bcx, sub_origins[origin]);
243 {bcx: bcx, ptrs: ptrs}