From 1741ef75ac7437e345265a4fa363431693771342 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 2 Jan 2012 13:26:51 +0100 Subject: [PATCH] Write out vtables for interface implementations Issue #1227 --- src/comp/middle/trans.rs | 37 ++++++++++++++++------- src/comp/middle/trans_common.rs | 2 +- src/comp/middle/trans_impl.rs | 52 ++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index c38dc5763f6e..65decadfc97f 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -80,13 +80,12 @@ fn type_of_explicit_args(cx: @crate_ctxt, sp: span, inputs: [ty::arg]) -> // - create_llargs_for_fn_args. // - new_fn_ctxt // - trans_args -fn type_of_fn(cx: @crate_ctxt, sp: span, - is_method: bool, inputs: [ty::arg], - output: ty::t, params: [ty::param_bounds]) - : non_ty_var(cx, output) -> TypeRef { +fn type_of_fn(cx: @crate_ctxt, sp: span, is_method: bool, inputs: [ty::arg], + output: ty::t, params: [ty::param_bounds]) -> TypeRef { let atys: [TypeRef] = []; // Arg 0: Output pointer. + check non_ty_var(cx, output); let out_ty = T_ptr(type_of_inner(cx, sp, output)); atys += [out_ty]; @@ -117,7 +116,6 @@ fn type_of_fn_from_ty(cx: @crate_ctxt, sp: span, fty: ty::t, // by returns_non_ty_var(t). Make that a postcondition // (see Issue #586) let ret_ty = ty::ty_fn_ret(cx.tcx, fty); - check non_ty_var(cx, ret_ty); ret type_of_fn(cx, sp, false, ty::ty_fn_args(cx.tcx, fty), ret_ty, param_bounds); } @@ -2771,8 +2769,6 @@ fn trans_object_field_inner(bcx: @block_ctxt, o: ValueRef, let fn_ty: ty::t = ty::mk_fn(tcx, mths[ix].fty); let ret_ty = ty::ty_fn_ret(tcx, fn_ty); // FIXME: constrain ty_obj? - check non_ty_var(ccx, ret_ty); - let ll_fn_ty = type_of_fn(ccx, bcx.sp, true, ty::ty_fn_args(tcx, fn_ty), ret_ty, []); v = Load(bcx, PointerCast(bcx, v, T_ptr(T_ptr(ll_fn_ty)))); @@ -5123,8 +5119,6 @@ fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef, ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mut: ast::imm})}; // FIXME: mk_nil should have a postcondition let nt = ty::mk_nil(ccx.tcx); - check non_ty_var(ccx, nt); - let llfty = type_of_fn(ccx, sp, false, [vecarg_ty], nt, []); let llfdecl = decl_fn(ccx.llmod, "_rust_main", lib::llvm::LLVMCCallConv, llfty); @@ -5223,7 +5217,6 @@ fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span, x: ty::t) -> TypeRef { alt ty::struct(cx.tcx, x) { ty::ty_native_fn(args, out) { - check non_ty_var(cx, out); ret type_of_fn(cx, sp, false, args, out, param_bounds); } } @@ -5377,7 +5370,7 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str], ast::item_tag(variants, _) { let i = 0u; for variant in variants { - let p = new_pt + [it.ident, variant.node.name, "discrim"]; + let p = new_pt + [variant.node.name, "discrim"]; let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx)); let discrim_gvar = str::as_buf(s, {|buf| llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf) @@ -5390,6 +5383,28 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str], i += 1u; } } + 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)); + let ty = ty::lookup_item_type(ccx.tcx, i_did).ty; + // FIXME[impl] use the same name as used in collect_items, for + // slightly more consistent symbol names? + let new_pt = pt + [ccx.names.next(it.ident)]; + let extra_tps = vec::map(tps, {|p| param_bounds(ccx, p)}); + let tbl = C_struct(vec::map(*ty::iface_methods(ccx.tcx, i_did), {|im| + alt vec::find(ms, {|m| m.ident == im.ident}) { + some(m) { + trans_impl::trans_wrapper(ccx, new_pt, extra_tps, m) + } + } + })); + let s = mangle_exported_name(ccx, new_pt + ["!vtable"], ty); + let vt_gvar = str::as_buf(s, {|buf| + llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf) + }); + llvm::LLVMSetInitializer(vt_gvar, tbl); + llvm::LLVMSetGlobalConstant(vt_gvar, True); + ccx.item_ids.insert(it.id, vt_gvar); + } _ { } } } diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 95cddc2af6d6..65dcd539510b 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -405,7 +405,7 @@ fn ty_str(tn: type_names, t: TypeRef) -> str { ret lib::llvm::type_to_str(tn, t); } -fn val_ty(v: ValueRef) -> TypeRef { ret llvm::LLVMTypeOf(v); } +fn val_ty(&&v: ValueRef) -> TypeRef { ret llvm::LLVMTypeOf(v); } fn val_str(tn: type_names, v: ValueRef) -> str { ret ty_str(tn, val_ty(v)); } diff --git a/src/comp/middle/trans_impl.rs b/src/comp/middle/trans_impl.rs index a393ebaf109f..095c73922874 100644 --- a/src/comp/middle/trans_impl.rs +++ b/src/comp/middle/trans_impl.rs @@ -2,8 +2,10 @@ import trans::*; import trans_common::*; import trans_build::*; import option::{some, none}; -import syntax::ast; +import syntax::{ast, ast_util}; +import back::link; import lib::llvm; +import llvm::llvm::{ValueRef, TypeRef, LLVMGetParam}; fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method], id: ast::node_id, tps: [ast::ty_param], @@ -19,3 +21,51 @@ fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method], } } } + +fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} { + let out_ty = llvm::llvm::LLVMGetReturnType(ft); + let n_args = llvm::llvm::LLVMCountParamTypes(ft); + let args = vec::init_elt(0 as TypeRef, n_args); + unsafe { llvm::llvm::LLVMGetParamTypes(ft, vec::to_ptr(args)); } + {inputs: args, output: out_ty} +} + +fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident], + extra_tps: [ty::param_bounds], m: @ast::method) -> ValueRef { + let real_fn = ccx.item_ids.get(m.id); + let {inputs: real_args, output: real_ret} = + llfn_arg_tys(llvm::llvm::LLVMGetElementType(val_ty(real_fn))); + let env_ty = T_ptr(T_struct([T_ptr(T_i8())] + + vec::map(extra_tps, + {|_p| T_ptr(ccx.tydesc_type)}))); + // FIXME[impl] filter and pass along dicts for bounds + let wrap_args = [env_ty] + vec::slice(real_args, 0u, 2u) + + vec::slice(real_args, 2u + vec::len(extra_tps), vec::len(real_args)); + let llfn_ty = T_fn(wrap_args, real_ret); + + let lcx = @{path: pt + ["wrapper", m.ident], module_path: [], + obj_typarams: [], obj_fields: [], ccx: ccx}; + let name = link::mangle_internal_name_by_path_and_seq(ccx, pt, m.ident); + let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfn_ty); + let fcx = new_fn_ctxt(lcx, ast_util::dummy_sp(), llfn); + let bcx = new_top_block_ctxt(fcx), lltop = bcx.llbb; + + let dict = LLVMGetParam(llfn, 0u); + // retptr, self + let args = [LLVMGetParam(llfn, 1u), LLVMGetParam(llfn, 2u)], i = 1; + // saved tydescs/dicts + for extra_tp in extra_tps { + args += [load_inbounds(bcx, dict, [0, i])]; + i += 1; + } + // the rest of the parameters + let i = 3u, params_total = llvm::llvm::LLVMCountParamTypes(llfn_ty); + while i < params_total { + args += [LLVMGetParam(llfn, i)]; + i += 1u; + } + Call(bcx, ccx.item_ids.get(m.id), args); + finish_fn(fcx, lltop); + ret llfn; +} +