Statically allocate static dicts

Issue #1436
This commit is contained in:
Marijn Haverbeke 2012-01-06 14:22:31 +01:00
parent 41a2d8495e
commit cf5c877fc0
3 changed files with 109 additions and 24 deletions

View File

@ -5689,6 +5689,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
discrim_symbols: new_int_hash::<str>(),
consts: new_int_hash::<ValueRef>(),
tydescs: ty::new_ty_hash(),
dicts: map::mk_hashmap(hash_dict_id, {|a, b| a == b}),
module_data: new_str_hash::<ValueRef>(),
lltypes: ty::new_ty_hash(),
names: namegen(0),

View File

@ -93,6 +93,7 @@ type crate_ctxt =
discrim_symbols: hashmap<ast::node_id, str>,
consts: hashmap<ast::node_id, ValueRef>,
tydescs: hashmap<ty::t, @tydesc_info>,
dicts: hashmap<dict_id, ValueRef>,
module_data: hashmap<str, ValueRef>,
lltypes: hashmap<ty::t, TypeRef>,
names: namegen,
@ -925,6 +926,24 @@ pure fn type_is_tup_like(cx: @block_ctxt, t: ty::t) -> bool {
ty::type_is_tup_like(tcx, t)
}
// Used to identify cached dictionaries
tag dict_param {
dict_param_dict(dict_id);
dict_param_ty(ty::t);
}
type dict_id = @{impl_def: ast::def_id, params: [dict_param]};
fn hash_dict_id(&&dp: dict_id) -> uint {
let h = syntax::ast_util::hash_def_id(dp.impl_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 += t; }
}
}
h
}
//
// Local Variables:
// mode: rust

View File

@ -5,8 +5,8 @@ import option::{some, none};
import syntax::{ast, ast_util};
import metadata::csearch;
import back::link;
import lib::llvm;
import llvm::llvm::{ValueRef, TypeRef, LLVMGetParam};
import lib::llvm::llvm;
import llvm::{ValueRef, TypeRef, LLVMGetParam};
fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
id: ast::node_id, tps: [ast::ty_param]) {
@ -76,10 +76,10 @@ fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
}
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 out_ty = llvm::LLVMGetReturnType(ft);
let n_args = llvm::LLVMCountParamTypes(ft);
let args = vec::init_elt(0 as TypeRef, n_args);
unsafe { llvm::llvm::LLVMGetParamTypes(ft, vec::to_ptr(args)); }
unsafe { llvm::LLVMGetParamTypes(ft, vec::to_ptr(args)); }
{inputs: args, output: out_ty}
}
@ -87,7 +87,7 @@ 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)));
llfn_arg_tys(llvm::LLVMGetElementType(val_ty(real_fn)));
let extra_ptrs = [];
for tp in extra_tps {
extra_ptrs += [T_ptr(ccx.tydesc_type)];
@ -121,7 +121,7 @@ fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
args += [load_inbounds(bcx, dict, [0, i as int])];
}
// the rest of the parameters
let i = 3u, params_total = llvm::llvm::LLVMCountParamTypes(llfn_ty);
let i = 3u, params_total = llvm::LLVMCountParamTypes(llfn_ty);
while i < params_total {
args += [LLVMGetParam(llfn, i)];
i += 1u;
@ -132,9 +132,84 @@ fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
ret llfn;
}
// FIXME[impl] cache these on the function level somehow
fn dict_is_static(tcx: ty::ctxt, origin: typeck::dict_origin) -> bool {
alt origin {
typeck::dict_static(_, ts, origs) {
vec::all(ts, {|t| !ty::type_contains_params(tcx, t)}) &&
vec::all(*origs, {|o| dict_is_static(tcx, o)})
}
typeck::dict_param(_, _) { false }
}
}
fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
let bcx = bcx, ccx = bcx_ccx(bcx);
alt origin {
typeck::dict_static(impl_did, tys, sub_origins) {
if dict_is_static(bcx_tcx(bcx), origin) {
ret rslt(bcx, get_static_dict(bcx, origin));
}
let {bcx, ptrs} = get_dict_ptrs(bcx, origin);
let pty = T_ptr(T_i8()), dict_ty = T_array(pty, vec::len(ptrs));
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;
}
rslt(bcx, PointerCast(bcx, dict, T_ptr(T_dict())))
}
typeck::dict_param(n_param, n_bound) {
rslt(bcx, option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound])
}
}
}
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;
if vec::len(ts) == 0u { ret @{impl_def: did, params: d_params}; }
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;
}
}
}
}
@{impl_def: did, params: d_params}
}
}
}
fn get_static_dict(bcx: @block_ctxt, origin: typeck::dict_origin)
-> ValueRef {
let ccx = bcx_ccx(bcx);
let id = dict_id(ccx.tcx, origin);
alt ccx.dicts.find(id) {
some(d) { ret d; }
none. {}
}
let ptrs = C_struct(get_dict_ptrs(bcx, origin).ptrs);
let name = ccx.names.next("dict");
let gvar = str::as_buf(name, {|buf|
llvm::LLVMAddGlobal(ccx.llmod, val_ty(ptrs), buf)
});
llvm::LLVMSetGlobalConstant(gvar, lib::llvm::True);
llvm::LLVMSetInitializer(gvar, ptrs);
llvm::LLVMSetLinkage(gvar,
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
let cast = llvm::LLVMConstPointerCast(gvar, T_ptr(T_dict()));
ccx.dicts.insert(id, cast);
cast
}
fn get_dict_ptrs(bcx: @block_ctxt, origin: typeck::dict_origin)
-> {bcx: @block_ctxt, ptrs: [ValueRef]} {
let ccx = bcx_ccx(bcx);
alt origin {
typeck::dict_static(impl_did, tys, sub_origins) {
let vtable = if impl_did.crate == ast::local_crate {
@ -144,9 +219,9 @@ fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
get_extern_const(ccx.externs, ccx.llmod, name, T_ptr(T_i8()))
};
let impl_params = ty::lookup_item_type(ccx.tcx, impl_did).bounds;
let ptrs = [vtable], i = 0u, origin = 0u, ti = none;
for param in *impl_params {
let rslt = get_tydesc(bcx, tys[i], false, tps_normal, ti).result;
let ptrs = [vtable], origin = 0u, ti = none, bcx = bcx;
vec::iter2(*impl_params, tys) {|param, ty|
let rslt = get_tydesc(bcx, ty, true, tps_normal, ti).result;
ptrs += [rslt.val];
bcx = rslt.bcx;
for bound in *param {
@ -160,18 +235,8 @@ fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
_ {}
}
}
i += 1u;
}
let pty = T_ptr(T_i8()), dict_ty = T_array(pty, vec::len(ptrs));
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;
}
rslt(bcx, PointerCast(bcx, dict, T_ptr(T_dict())))
}
typeck::dict_param(n_param, n_bound) {
rslt(bcx, option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound])
{bcx: bcx, ptrs: ptrs}
}
}
}
}