Make binding of fns with bounded type parameters work

Interns non-static dicts to heap-allocated equivalents so that they no
longer have stack scope.

Closes #1436
This commit is contained in:
Marijn Haverbeke 2012-01-06 17:29:06 +01:00
parent d23e2052e0
commit 822acdd170
7 changed files with 81 additions and 6 deletions

View File

@ -2,7 +2,7 @@
import driver::session;
import middle::trans;
import middle::trans_common::{T_fn, T_i1, T_i8, T_i32,
T_int, T_nil,
T_int, T_nil, T_dict,
T_opaque_vec, T_ptr,
T_size_t, T_void};
import lib::llvm::type_names;
@ -20,6 +20,7 @@ type upcalls =
create_shared_type_desc: ValueRef,
free_shared_type_desc: ValueRef,
get_type_desc: ValueRef,
intern_dict: ValueRef,
vec_grow: ValueRef,
vec_push: ValueRef,
cmp_type: ValueRef,
@ -76,6 +77,8 @@ fn declare_upcalls(targ_cfg: @session::config,
size_t, size_t,
T_ptr(T_ptr(tydesc_type)), int_t],
T_ptr(tydesc_type)),
intern_dict:
d("intern_dict", [size_t, T_ptr(T_dict())], T_ptr(T_dict())),
vec_grow:
dv("vec_grow", [T_ptr(T_ptr(opaque_vec_t)), int_t]),
vec_push:

View File

@ -461,18 +461,24 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
let (outgoing_fty_real, lltydescs, param_bounds) = alt f_res.generic {
none. { (outgoing_fty, [], @[]) }
some(ginfo) {
for bounds in *ginfo.param_bounds {
let tds = [], orig = 0u;
vec::iter2(ginfo.tydescs, *ginfo.param_bounds) {|td, bounds|
tds += [td];
for bound in *bounds {
alt bound {
ty::bound_iface(_) {
fail "FIXME[impl] binding bounded types not implemented";
let dict = trans_impl::get_dict(
bcx, option::get(ginfo.origins)[orig]);
tds += [PointerCast(bcx, dict.val, val_ty(td))];
orig += 1u;
bcx = dict.bcx;
}
_ {}
}
}
}
lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
(ginfo.item_type, ginfo.tydescs, ginfo.param_bounds)
(ginfo.item_type, tds, ginfo.param_bounds)
}
};

View File

@ -143,9 +143,10 @@ fn dict_is_static(tcx: ty::ctxt, origin: typeck::dict_origin) -> bool {
}
fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
let ccx = bcx_ccx(bcx);
alt origin {
typeck::dict_static(impl_did, tys, sub_origins) {
if dict_is_static(bcx_tcx(bcx), origin) {
if dict_is_static(ccx.tcx, origin) {
ret rslt(bcx, get_static_dict(bcx, origin));
}
let {bcx, ptrs} = get_dict_ptrs(bcx, origin);
@ -155,7 +156,10 @@ fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
Store(bcx, PointerCast(bcx, ptr, pty), GEPi(bcx, dict, [0, i]));
i += 1;
}
rslt(bcx, PointerCast(bcx, dict, T_ptr(T_dict())))
dict = Call(bcx, ccx.upcalls.intern_dict,
[C_uint(ccx, vec::len(ptrs)),
PointerCast(bcx, dict, T_ptr(T_dict()))]);
rslt(bcx, dict)
}
typeck::dict_param(n_param, n_bound) {
rslt(bcx, option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound])

View File

@ -45,8 +45,30 @@ rust_crate_cache::get_type_desc(size_t size,
return td;
}
void**
rust_crate_cache::get_dict(size_t n_fields, void** dict) {
rust_hashable_dict *found = NULL;
uintptr_t key = 0;
for (size_t i = 0; i < n_fields; ++i) key ^= (uintptr_t)dict[i];
size_t keysz = sizeof(uintptr_t);
HASH_FIND(hh, this->dicts, &key, keysz, found);
if (found) { printf("found!\n"); return &(found->fields[0]); }
printf("not found\n");
size_t dictsz = n_fields * sizeof(void*);
found = (rust_hashable_dict*)
sched->kernel->malloc(keysz + sizeof(UT_hash_handle) + dictsz,
"crate cache dict");
if (!found) return NULL;
found->key = key;
void** retptr = &(found->fields[0]);
memcpy(retptr, dict, dictsz);
HASH_ADD(hh, this->dicts, key, keysz, found);
return retptr;
}
rust_crate_cache::rust_crate_cache(rust_scheduler *sched)
: type_descs(NULL),
dicts(NULL),
sched(sched),
idx(0)
{
@ -62,6 +84,11 @@ rust_crate_cache::flush() {
DLOG(sched, mem, "rust_crate_cache::flush() tydesc %" PRIxPTR, d);
sched->kernel->free(d);
}
while (dicts) {
rust_hashable_dict *d = dicts;
HASH_DEL(dicts, d);
sched->kernel->free(d);
}
}
rust_crate_cache::~rust_crate_cache()

View File

@ -11,6 +11,12 @@
struct rust_scheduler;
struct rust_hashable_dict {
uintptr_t key;
UT_hash_handle hh;
void* fields[0];
};
class rust_crate_cache {
public:
type_desc *get_type_desc(size_t size,
@ -18,10 +24,12 @@ public:
size_t n_descs,
type_desc const **descs,
uintptr_t n_obj_params);
void** get_dict(size_t n_fields, void** dict);
private:
type_desc *type_descs;
rust_hashable_dict *dicts;
public:

View File

@ -336,6 +336,32 @@ upcall_get_type_desc(void *curr_crate, // ignored, legacy compat.
return args.retval;
}
/**********************************************************************
* Called to get a heap-allocated dict. These are interned and kept
* around indefinitely
*/
struct s_intern_dict_args {
size_t n_fields;
void** dict;
void** res;
};
extern "C" CDECL void
upcall_s_intern_dict(s_intern_dict_args *args) {
rust_task *task = rust_scheduler::get_task();
LOG_UPCALL_ENTRY(task);
rust_crate_cache *cache = task->get_crate_cache();
args->res = cache->get_dict(args->n_fields, args->dict);
}
extern "C" CDECL void**
upcall_intern_dict(size_t n_fields, void** dict) {
s_intern_dict_args args = {n_fields, dict, 0 };
UPCALL_SWITCH_STACK(&args, upcall_s_intern_dict);
return args.res;
}
/**********************************************************************/
struct s_vec_grow_args {

View File

@ -62,6 +62,7 @@ upcall_free
upcall_create_shared_type_desc
upcall_free_shared_type_desc
upcall_get_type_desc
upcall_intern_dict
upcall_log_type
upcall_malloc
upcall_rust_personality