From: Marijn Haverbeke Date: Fri, 6 Jan 2012 16:29:06 +0000 (+0100) Subject: Make binding of fns with bounded type parameters work X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=822acdd1703af1714cb084a76c10937713339f6d;p=rust.git 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 --- diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index d488a0fa00d..a6bf286a2a8 100644 --- a/src/comp/back/upcall.rs +++ b/src/comp/back/upcall.rs @@ -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 @@ 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 decl(llmod: ModuleRef, name: str, tys: [TypeRef], rv: TypeRef) -> 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: diff --git a/src/comp/middle/trans_closure.rs b/src/comp/middle/trans_closure.rs index 7759072f028..4a43b2ead87 100644 --- a/src/comp/middle/trans_closure.rs +++ b/src/comp/middle/trans_closure.rs @@ -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) } }; diff --git a/src/comp/middle/trans_impl.rs b/src/comp/middle/trans_impl.rs index daee48c8630..1f3f4395366 100644 --- a/src/comp/middle/trans_impl.rs +++ b/src/comp/middle/trans_impl.rs @@ -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]) diff --git a/src/rt/rust_crate_cache.cpp b/src/rt/rust_crate_cache.cpp index 47b402102f3..6fcb0fc699e 100644 --- a/src/rt/rust_crate_cache.cpp +++ b/src/rt/rust_crate_cache.cpp @@ -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() diff --git a/src/rt/rust_scheduler.h b/src/rt/rust_scheduler.h index 39fd4a07f81..75dce82d318 100644 --- a/src/rt/rust_scheduler.h +++ b/src/rt/rust_scheduler.h @@ -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: diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 7d64842994e..6baac699e8f 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -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 { diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 8353483ebf2..86b41fcb256 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -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