Skip to content

Commit cf5c877

Browse files
committed
Statically allocate static dicts
Issue #1436
1 parent 41a2d84 commit cf5c877

File tree

3 files changed

+109
-24
lines changed

3 files changed

+109
-24
lines changed

src/comp/middle/trans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5689,6 +5689,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
56895689
discrim_symbols: new_int_hash::<str>(),
56905690
consts: new_int_hash::<ValueRef>(),
56915691
tydescs: ty::new_ty_hash(),
5692+
dicts: map::mk_hashmap(hash_dict_id, {|a, b| a == b}),
56925693
module_data: new_str_hash::<ValueRef>(),
56935694
lltypes: ty::new_ty_hash(),
56945695
names: namegen(0),

src/comp/middle/trans_common.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ type crate_ctxt =
9393
discrim_symbols: hashmap<ast::node_id, str>,
9494
consts: hashmap<ast::node_id, ValueRef>,
9595
tydescs: hashmap<ty::t, @tydesc_info>,
96+
dicts: hashmap<dict_id, ValueRef>,
9697
module_data: hashmap<str, ValueRef>,
9798
lltypes: hashmap<ty::t, TypeRef>,
9899
names: namegen,
@@ -925,6 +926,24 @@ pure fn type_is_tup_like(cx: @block_ctxt, t: ty::t) -> bool {
925926
ty::type_is_tup_like(tcx, t)
926927
}
927928

929+
// Used to identify cached dictionaries
930+
tag dict_param {
931+
dict_param_dict(dict_id);
932+
dict_param_ty(ty::t);
933+
}
934+
type dict_id = @{impl_def: ast::def_id, params: [dict_param]};
935+
fn hash_dict_id(&&dp: dict_id) -> uint {
936+
let h = syntax::ast_util::hash_def_id(dp.impl_def);
937+
for param in dp.params {
938+
h = h << 2u;
939+
alt param {
940+
dict_param_dict(d) { h += hash_dict_id(d); }
941+
dict_param_ty(t) { h += t; }
942+
}
943+
}
944+
h
945+
}
946+
928947
//
929948
// Local Variables:
930949
// mode: rust

src/comp/middle/trans_impl.rs

Lines changed: 89 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import option::{some, none};
55
import syntax::{ast, ast_util};
66
import metadata::csearch;
77
import back::link;
8-
import lib::llvm;
9-
import llvm::llvm::{ValueRef, TypeRef, LLVMGetParam};
8+
import lib::llvm::llvm;
9+
import llvm::{ValueRef, TypeRef, LLVMGetParam};
1010

1111
fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
1212
id: ast::node_id, tps: [ast::ty_param]) {
@@ -76,18 +76,18 @@ fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
7676
}
7777

7878
fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
79-
let out_ty = llvm::llvm::LLVMGetReturnType(ft);
80-
let n_args = llvm::llvm::LLVMCountParamTypes(ft);
79+
let out_ty = llvm::LLVMGetReturnType(ft);
80+
let n_args = llvm::LLVMCountParamTypes(ft);
8181
let args = vec::init_elt(0 as TypeRef, n_args);
82-
unsafe { llvm::llvm::LLVMGetParamTypes(ft, vec::to_ptr(args)); }
82+
unsafe { llvm::LLVMGetParamTypes(ft, vec::to_ptr(args)); }
8383
{inputs: args, output: out_ty}
8484
}
8585

8686
fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
8787
extra_tps: [ty::param_bounds], m: @ast::method) -> ValueRef {
8888
let real_fn = ccx.item_ids.get(m.id);
8989
let {inputs: real_args, output: real_ret} =
90-
llfn_arg_tys(llvm::llvm::LLVMGetElementType(val_ty(real_fn)));
90+
llfn_arg_tys(llvm::LLVMGetElementType(val_ty(real_fn)));
9191
let extra_ptrs = [];
9292
for tp in extra_tps {
9393
extra_ptrs += [T_ptr(ccx.tydesc_type)];
@@ -121,7 +121,7 @@ fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
121121
args += [load_inbounds(bcx, dict, [0, i as int])];
122122
}
123123
// the rest of the parameters
124-
let i = 3u, params_total = llvm::llvm::LLVMCountParamTypes(llfn_ty);
124+
let i = 3u, params_total = llvm::LLVMCountParamTypes(llfn_ty);
125125
while i < params_total {
126126
args += [LLVMGetParam(llfn, i)];
127127
i += 1u;
@@ -132,9 +132,84 @@ fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
132132
ret llfn;
133133
}
134134

135-
// FIXME[impl] cache these on the function level somehow
135+
fn dict_is_static(tcx: ty::ctxt, origin: typeck::dict_origin) -> bool {
136+
alt origin {
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)})
140+
}
141+
typeck::dict_param(_, _) { false }
142+
}
143+
}
144+
136145
fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
137-
let bcx = bcx, ccx = bcx_ccx(bcx);
146+
alt origin {
147+
typeck::dict_static(impl_did, tys, sub_origins) {
148+
if dict_is_static(bcx_tcx(bcx), origin) {
149+
ret rslt(bcx, get_static_dict(bcx, origin));
150+
}
151+
let {bcx, ptrs} = get_dict_ptrs(bcx, origin);
152+
let pty = T_ptr(T_i8()), dict_ty = T_array(pty, vec::len(ptrs));
153+
let dict = alloca(bcx, dict_ty), i = 0;
154+
for ptr in ptrs {
155+
Store(bcx, PointerCast(bcx, ptr, pty), GEPi(bcx, dict, [0, i]));
156+
i += 1;
157+
}
158+
rslt(bcx, PointerCast(bcx, dict, T_ptr(T_dict())))
159+
}
160+
typeck::dict_param(n_param, n_bound) {
161+
rslt(bcx, option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound])
162+
}
163+
}
164+
}
165+
166+
fn dict_id(tcx: ty::ctxt, origin: typeck::dict_origin) -> dict_id {
167+
alt origin {
168+
typeck::dict_static(did, ts, origs) {
169+
let d_params = [], orig = 0u;
170+
if vec::len(ts) == 0u { ret @{impl_def: did, params: d_params}; }
171+
let impl_params = ty::lookup_item_type(tcx, did).bounds;
172+
vec::iter2(ts, *impl_params) {|t, bounds|
173+
d_params += [dict_param_ty(t)];
174+
for bound in *bounds {
175+
alt bound {
176+
ty::bound_iface(_) {
177+
d_params += [dict_param_dict(dict_id(tcx, origs[orig]))];
178+
orig += 1u;
179+
}
180+
}
181+
}
182+
}
183+
@{impl_def: did, params: d_params}
184+
}
185+
}
186+
}
187+
188+
fn get_static_dict(bcx: @block_ctxt, origin: typeck::dict_origin)
189+
-> ValueRef {
190+
let ccx = bcx_ccx(bcx);
191+
let id = dict_id(ccx.tcx, origin);
192+
alt ccx.dicts.find(id) {
193+
some(d) { ret d; }
194+
none. {}
195+
}
196+
let ptrs = C_struct(get_dict_ptrs(bcx, origin).ptrs);
197+
let name = ccx.names.next("dict");
198+
let gvar = str::as_buf(name, {|buf|
199+
llvm::LLVMAddGlobal(ccx.llmod, val_ty(ptrs), buf)
200+
});
201+
llvm::LLVMSetGlobalConstant(gvar, lib::llvm::True);
202+
llvm::LLVMSetInitializer(gvar, ptrs);
203+
llvm::LLVMSetLinkage(gvar,
204+
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
205+
let cast = llvm::LLVMConstPointerCast(gvar, T_ptr(T_dict()));
206+
ccx.dicts.insert(id, cast);
207+
cast
208+
}
209+
210+
fn get_dict_ptrs(bcx: @block_ctxt, origin: typeck::dict_origin)
211+
-> {bcx: @block_ctxt, ptrs: [ValueRef]} {
212+
let ccx = bcx_ccx(bcx);
138213
alt origin {
139214
typeck::dict_static(impl_did, tys, sub_origins) {
140215
let vtable = if impl_did.crate == ast::local_crate {
@@ -144,9 +219,9 @@ fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
144219
get_extern_const(ccx.externs, ccx.llmod, name, T_ptr(T_i8()))
145220
};
146221
let impl_params = ty::lookup_item_type(ccx.tcx, impl_did).bounds;
147-
let ptrs = [vtable], i = 0u, origin = 0u, ti = none;
148-
for param in *impl_params {
149-
let rslt = get_tydesc(bcx, tys[i], false, tps_normal, ti).result;
222+
let ptrs = [vtable], origin = 0u, ti = none, bcx = bcx;
223+
vec::iter2(*impl_params, tys) {|param, ty|
224+
let rslt = get_tydesc(bcx, ty, true, tps_normal, ti).result;
150225
ptrs += [rslt.val];
151226
bcx = rslt.bcx;
152227
for bound in *param {
@@ -160,18 +235,8 @@ fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
160235
_ {}
161236
}
162237
}
163-
i += 1u;
164238
}
165-
let pty = T_ptr(T_i8()), dict_ty = T_array(pty, vec::len(ptrs));
166-
let dict = alloca(bcx, dict_ty), i = 0;
167-
for ptr in ptrs {
168-
Store(bcx, PointerCast(bcx, ptr, pty), GEPi(bcx, dict, [0, i]));
169-
i += 1;
170-
}
171-
rslt(bcx, PointerCast(bcx, dict, T_ptr(T_dict())))
172-
}
173-
typeck::dict_param(n_param, n_bound) {
174-
rslt(bcx, option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound])
239+
{bcx: bcx, ptrs: ptrs}
175240
}
176241
}
177-
}
242+
}

0 commit comments

Comments
 (0)