rustc: Root resources with addrspaces.
This commit is contained in:
parent
c8daf2ac16
commit
c2e99ba826
@ -54,7 +54,7 @@ fn trans_opt(bcx: block, o: opt) -> opt_result {
|
||||
let cell = empty_dest_cell();
|
||||
bcx = tvec::trans_estr(bcx, s, some(ast::vstore_uniq),
|
||||
by_val(cell));
|
||||
add_clean_temp(bcx, *cell, strty);
|
||||
add_clean_temp_immediate(bcx, *cell, strty);
|
||||
return single_result(rslt(bcx, *cell));
|
||||
}
|
||||
_ => {
|
||||
|
@ -486,6 +486,20 @@ fn note_unique_llvm_symbol(ccx: @crate_ctxt, sym: ~str) {
|
||||
ccx.all_llvm_symbols.insert(sym, ());
|
||||
}
|
||||
|
||||
// Chooses the addrspace for newly declared types.
|
||||
fn declare_tydesc_addrspace(ccx: @crate_ctxt, t: ty::t) -> addrspace {
|
||||
if !ty::type_needs_drop(ccx.tcx, t) {
|
||||
return default_addrspace;
|
||||
} else if ty::type_is_immediate(t) {
|
||||
// For immediate types, we don't actually need an addrspace, because
|
||||
// e.g. boxed types include pointers to their contents which are
|
||||
// already correctly tagged with addrspaces.
|
||||
return default_addrspace;
|
||||
} else {
|
||||
return ccx.next_addrspace();
|
||||
}
|
||||
}
|
||||
|
||||
// Generates the declaration for (but doesn't emit) a type descriptor.
|
||||
fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
||||
let _icx = ccx.insn_ctxt("declare_tydesc");
|
||||
@ -499,6 +513,7 @@ fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
||||
|
||||
let llsize = llsize_of(ccx, llty);
|
||||
let llalign = llalign_of(ccx, llty);
|
||||
let addrspace = declare_tydesc_addrspace(ccx, t);
|
||||
//XXX this triggers duplicate LLVM symbols
|
||||
let name = if false /*ccx.sess.opts.debuginfo*/ {
|
||||
mangle_internal_name_by_type_only(ccx, t, ~"tydesc")
|
||||
@ -513,6 +528,7 @@ fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
||||
tydesc: gvar,
|
||||
size: llsize,
|
||||
align: llalign,
|
||||
addrspace: addrspace,
|
||||
mut take_glue: none,
|
||||
mut drop_glue: none,
|
||||
mut free_glue: none,
|
||||
@ -1275,6 +1291,16 @@ fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block {
|
||||
return cx;
|
||||
}
|
||||
|
||||
fn drop_ty_root(bcx: block, v: ValueRef, rooted: bool, t: ty::t) -> block {
|
||||
if rooted {
|
||||
// NB: v is a raw ptr to an addrspace'd ptr to the value.
|
||||
let v = PointerCast(bcx, Load(bcx, v), T_ptr(type_of(bcx.ccx(), t)));
|
||||
drop_ty(bcx, v, t)
|
||||
} else {
|
||||
drop_ty(bcx, v, t)
|
||||
}
|
||||
}
|
||||
|
||||
fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
|
||||
let _icx = bcx.insn_ctxt("drop_ty_immediate");
|
||||
match ty::get(t).struct {
|
||||
@ -2751,7 +2777,7 @@ fn trans_lval(cx: block, e: @ast::expr) -> lval_result {
|
||||
fn non_gc_box_cast(cx: block, val: ValueRef) -> ValueRef {
|
||||
debug!("non_gc_box_cast");
|
||||
add_comment(cx, ~"non_gc_box_cast");
|
||||
assert(llvm::LLVMGetPointerAddressSpace(val_ty(val)) as uint == 1u);
|
||||
assert(llvm::LLVMGetPointerAddressSpace(val_ty(val)) == gc_box_addrspace);
|
||||
let non_gc_t = T_ptr(llvm::LLVMGetElementType(val_ty(val)));
|
||||
PointerCast(cx, val, non_gc_t)
|
||||
}
|
||||
@ -3639,12 +3665,12 @@ fn trans_temp_lval(bcx: block, e: @ast::expr) -> lval_result {
|
||||
} else if ty::type_is_immediate(ty) {
|
||||
let cell = empty_dest_cell();
|
||||
bcx = trans_expr(bcx, e, by_val(cell));
|
||||
add_clean_temp(bcx, *cell, ty);
|
||||
add_clean_temp_immediate(bcx, *cell, ty);
|
||||
return {bcx: bcx, val: *cell, kind: lv_temporary};
|
||||
} else {
|
||||
let scratch = alloc_ty(bcx, ty);
|
||||
let bcx = trans_expr_save_in(bcx, e, scratch);
|
||||
add_clean_temp(bcx, scratch, ty);
|
||||
add_clean_temp_mem(bcx, scratch, ty);
|
||||
return {bcx: bcx, val: scratch, kind: lv_temporary};
|
||||
}
|
||||
}
|
||||
@ -5815,6 +5841,7 @@ fn trans_crate(sess: session::session,
|
||||
module_data: str_hash::<ValueRef>(),
|
||||
lltypes: ty::new_ty_hash(),
|
||||
names: new_namegen(sess.parse_sess.interner),
|
||||
next_addrspace: new_addrspace_gen(),
|
||||
symbol_hasher: symbol_hasher,
|
||||
type_hashcodes: ty::new_ty_hash(),
|
||||
type_short_names: ty::new_ty_hash(),
|
||||
|
@ -30,11 +30,28 @@ fn new_namegen(intr: ident_interner) -> namegen {
|
||||
};
|
||||
}
|
||||
|
||||
type addrspace = c_uint;
|
||||
|
||||
// Address spaces communicate to LLVM which destructors need to run for
|
||||
// specifc types.
|
||||
// 0 is ignored by the GC, and is used for all non-GC'd pointers.
|
||||
// 1 is for opaque GC'd boxes.
|
||||
// >= 2 are for specific types (e.g. resources).
|
||||
const default_addrspace: addrspace = 0;
|
||||
const gc_box_addrspace: addrspace = 1;
|
||||
|
||||
type addrspace_gen = fn@() -> addrspace;
|
||||
fn new_addrspace_gen() -> addrspace_gen {
|
||||
let i = @mut 1;
|
||||
return fn@() -> addrspace { *i += 1; *i };
|
||||
}
|
||||
|
||||
type tydesc_info =
|
||||
{ty: ty::t,
|
||||
tydesc: ValueRef,
|
||||
size: ValueRef,
|
||||
align: ValueRef,
|
||||
addrspace: addrspace,
|
||||
mut take_glue: option<ValueRef>,
|
||||
mut drop_glue: option<ValueRef>,
|
||||
mut free_glue: option<ValueRef>,
|
||||
@ -118,6 +135,7 @@ type crate_ctxt = {
|
||||
module_data: hashmap<~str, ValueRef>,
|
||||
lltypes: hashmap<ty::t, TypeRef>,
|
||||
names: namegen,
|
||||
next_addrspace: addrspace_gen,
|
||||
symbol_hasher: @hash::State,
|
||||
type_hashcodes: hashmap<ty::t, ~str>,
|
||||
type_short_names: hashmap<ty::t, ~str>,
|
||||
@ -254,47 +272,64 @@ fn cleanup_type(cx: ty::ctxt, ty: ty::t) -> cleantype {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_clean(cx: block, val: ValueRef, ty: ty::t) {
|
||||
if !ty::type_needs_drop(cx.tcx(), ty) { return; }
|
||||
// This is not the same as base::root_value, which appears to be the vestigial
|
||||
// remains of the previous GC regime. In the new GC, we can identify
|
||||
// immediates on the stack without difficulty, but have trouble knowing where
|
||||
// non-immediates are on the stack. For non-immediates, we must add an
|
||||
// additional level of indirection, which allows us to alloca a pointer with
|
||||
// the right addrspace.
|
||||
fn root_for_cleanup(bcx: block, v: ValueRef, t: ty::t)
|
||||
-> {root: ValueRef, rooted: bool} {
|
||||
let ccx = bcx.ccx();
|
||||
|
||||
let addrspace = base::get_tydesc(ccx, t).addrspace;
|
||||
if addrspace > gc_box_addrspace {
|
||||
let llty = type_of::type_of_rooted(ccx, t);
|
||||
let root = base::alloca(bcx, llty);
|
||||
build::Store(bcx, build::PointerCast(bcx, v, llty), root);
|
||||
{root: root, rooted: true}
|
||||
} else {
|
||||
{root: v, rooted: false}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_clean(bcx: block, val: ValueRef, t: ty::t) {
|
||||
if !ty::type_needs_drop(bcx.tcx(), t) { return; }
|
||||
debug!("add_clean(%s, %s, %s)",
|
||||
cx.to_str(), val_str(cx.ccx().tn, val),
|
||||
ty_to_str(cx.ccx().tcx, ty));
|
||||
let cleanup_type = cleanup_type(cx.tcx(), ty);
|
||||
do in_scope_cx(cx) |info| {
|
||||
vec::push(info.cleanups, clean(|a| base::drop_ty(a, val, ty),
|
||||
cleanup_type));
|
||||
bcx.to_str(), val_str(bcx.ccx().tn, val),
|
||||
ty_to_str(bcx.ccx().tcx, t));
|
||||
let {root, rooted} = root_for_cleanup(bcx, val, t);
|
||||
let cleanup_type = cleanup_type(bcx.tcx(), t);
|
||||
do in_scope_cx(bcx) |info| {
|
||||
vec::push(info.cleanups,
|
||||
clean(|a| base::drop_ty_root(a, root, rooted, t),
|
||||
cleanup_type));
|
||||
scope_clean_changed(info);
|
||||
}
|
||||
}
|
||||
fn add_clean_temp(cx: block, val: ValueRef, ty: ty::t) {
|
||||
fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) {
|
||||
if !ty::type_needs_drop(cx.tcx(), ty) { return; }
|
||||
debug!("add_clean_temp(%s, %s, %s)",
|
||||
cx.to_str(), val_str(cx.ccx().tn, val),
|
||||
ty_to_str(cx.ccx().tcx, ty));
|
||||
let cleanup_type = cleanup_type(cx.tcx(), ty);
|
||||
fn do_drop(bcx: block, val: ValueRef, ty: ty::t) ->
|
||||
block {
|
||||
if ty::type_is_immediate(ty) {
|
||||
return base::drop_ty_immediate(bcx, val, ty);
|
||||
} else {
|
||||
return base::drop_ty(bcx, val, ty);
|
||||
}
|
||||
}
|
||||
do in_scope_cx(cx) |info| {
|
||||
vec::push(info.cleanups, clean_temp(val, |a| do_drop(a, val, ty),
|
||||
cleanup_type));
|
||||
scope_clean_changed(info);
|
||||
}
|
||||
}
|
||||
fn add_clean_temp_mem(cx: block, val: ValueRef, ty: ty::t) {
|
||||
if !ty::type_needs_drop(cx.tcx(), ty) { return; }
|
||||
debug!("add_clean_temp_mem(%s, %s, %s)",
|
||||
debug!("add_clean_temp_immediate(%s, %s, %s)",
|
||||
cx.to_str(), val_str(cx.ccx().tn, val),
|
||||
ty_to_str(cx.ccx().tcx, ty));
|
||||
let cleanup_type = cleanup_type(cx.tcx(), ty);
|
||||
do in_scope_cx(cx) |info| {
|
||||
vec::push(info.cleanups,
|
||||
clean_temp(val, |a| base::drop_ty(a, val, ty),
|
||||
clean_temp(val, |a| base::drop_ty_immediate(a, val, ty),
|
||||
cleanup_type));
|
||||
scope_clean_changed(info);
|
||||
}
|
||||
}
|
||||
fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) {
|
||||
if !ty::type_needs_drop(bcx.tcx(), t) { return; }
|
||||
debug!("add_clean_temp_mem(%s, %s, %s)",
|
||||
bcx.to_str(), val_str(bcx.ccx().tn, val),
|
||||
ty_to_str(bcx.ccx().tcx, t));
|
||||
let {root, rooted} = root_for_cleanup(bcx, val, t);
|
||||
let cleanup_type = cleanup_type(bcx.tcx(), t);
|
||||
do in_scope_cx(bcx) |info| {
|
||||
vec::push(info.cleanups,
|
||||
clean_temp(val, |a| base::drop_ty_root(a, root, rooted, t),
|
||||
cleanup_type));
|
||||
scope_clean_changed(info);
|
||||
}
|
||||
@ -607,7 +642,11 @@ fn T_fn_pair(cx: @crate_ctxt, tfn: TypeRef) -> TypeRef {
|
||||
}
|
||||
|
||||
fn T_ptr(t: TypeRef) -> TypeRef {
|
||||
return llvm::LLVMPointerType(t, 0u as c_uint);
|
||||
return llvm::LLVMPointerType(t, default_addrspace);
|
||||
}
|
||||
|
||||
fn T_root(t: TypeRef, addrspace: addrspace) -> TypeRef {
|
||||
return llvm::LLVMPointerType(t, addrspace);
|
||||
}
|
||||
|
||||
fn T_struct(elts: ~[TypeRef]) -> TypeRef unsafe {
|
||||
@ -738,8 +777,7 @@ fn T_box(cx: @crate_ctxt, t: TypeRef) -> TypeRef {
|
||||
}
|
||||
|
||||
fn T_box_ptr(t: TypeRef) -> TypeRef {
|
||||
const box_addrspace: uint = 1u;
|
||||
return llvm::LLVMPointerType(t, box_addrspace as c_uint);
|
||||
return llvm::LLVMPointerType(t, gc_box_addrspace);
|
||||
}
|
||||
|
||||
fn T_opaque_box(cx: @crate_ctxt) -> TypeRef {
|
||||
@ -755,8 +793,7 @@ fn T_unique(cx: @crate_ctxt, t: TypeRef) -> TypeRef {
|
||||
}
|
||||
|
||||
fn T_unique_ptr(t: TypeRef) -> TypeRef {
|
||||
const unique_addrspace: uint = 1u;
|
||||
return llvm::LLVMPointerType(t, unique_addrspace as c_uint);
|
||||
return llvm::LLVMPointerType(t, gc_box_addrspace);
|
||||
}
|
||||
|
||||
fn T_port(cx: @crate_ctxt, _t: TypeRef) -> TypeRef {
|
||||
|
@ -12,6 +12,7 @@ export type_of_fn_from_ty;
|
||||
export type_of_fn;
|
||||
export type_of_glue_fn;
|
||||
export type_of_non_gc_box;
|
||||
export type_of_rooted;
|
||||
|
||||
fn type_of_explicit_args(cx: @crate_ctxt,
|
||||
inputs: ~[ty::arg]) -> ~[TypeRef] {
|
||||
@ -245,6 +246,13 @@ fn type_of_dtor(ccx: @crate_ctxt, self_ty: ty::t) -> TypeRef {
|
||||
llvm::LLVMVoidType())
|
||||
}
|
||||
|
||||
fn type_of_rooted(ccx: @crate_ctxt, t: ty::t) -> TypeRef {
|
||||
let addrspace = base::get_tydesc(ccx, t).addrspace;
|
||||
debug!{"type_of_rooted %s in addrspace %u",
|
||||
ty_to_str(ccx.tcx, t), addrspace as uint};
|
||||
return T_root(type_of(ccx, t), addrspace);
|
||||
}
|
||||
|
||||
fn type_of_glue_fn(ccx: @crate_ctxt, t: ty::t) -> TypeRef {
|
||||
let tydescpp = T_ptr(T_ptr(ccx.tydesc_type));
|
||||
let llty = T_ptr(type_of(ccx, t));
|
||||
|
Loading…
Reference in New Issue
Block a user