rustc: Root resources with addrspaces.

This commit is contained in:
Elliott Slaughter 2012-08-06 10:53:38 -07:00
parent c8daf2ac16
commit c2e99ba826
4 changed files with 112 additions and 40 deletions

View File

@ -54,7 +54,7 @@ fn trans_opt(bcx: block, o: opt) -> opt_result {
let cell = empty_dest_cell(); let cell = empty_dest_cell();
bcx = tvec::trans_estr(bcx, s, some(ast::vstore_uniq), bcx = tvec::trans_estr(bcx, s, some(ast::vstore_uniq),
by_val(cell)); by_val(cell));
add_clean_temp(bcx, *cell, strty); add_clean_temp_immediate(bcx, *cell, strty);
return single_result(rslt(bcx, *cell)); return single_result(rslt(bcx, *cell));
} }
_ => { _ => {

View File

@ -486,6 +486,20 @@ fn note_unique_llvm_symbol(ccx: @crate_ctxt, sym: ~str) {
ccx.all_llvm_symbols.insert(sym, ()); 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. // Generates the declaration for (but doesn't emit) a type descriptor.
fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info { fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
let _icx = ccx.insn_ctxt("declare_tydesc"); 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 llsize = llsize_of(ccx, llty);
let llalign = llalign_of(ccx, llty); let llalign = llalign_of(ccx, llty);
let addrspace = declare_tydesc_addrspace(ccx, t);
//XXX this triggers duplicate LLVM symbols //XXX this triggers duplicate LLVM symbols
let name = if false /*ccx.sess.opts.debuginfo*/ { let name = if false /*ccx.sess.opts.debuginfo*/ {
mangle_internal_name_by_type_only(ccx, t, ~"tydesc") 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, tydesc: gvar,
size: llsize, size: llsize,
align: llalign, align: llalign,
addrspace: addrspace,
mut take_glue: none, mut take_glue: none,
mut drop_glue: none, mut drop_glue: none,
mut free_glue: none, mut free_glue: none,
@ -1275,6 +1291,16 @@ fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block {
return cx; 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 { fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
let _icx = bcx.insn_ctxt("drop_ty_immediate"); let _icx = bcx.insn_ctxt("drop_ty_immediate");
match ty::get(t).struct { 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 { fn non_gc_box_cast(cx: block, val: ValueRef) -> ValueRef {
debug!("non_gc_box_cast"); debug!("non_gc_box_cast");
add_comment(cx, ~"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))); let non_gc_t = T_ptr(llvm::LLVMGetElementType(val_ty(val)));
PointerCast(cx, val, non_gc_t) 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) { } else if ty::type_is_immediate(ty) {
let cell = empty_dest_cell(); let cell = empty_dest_cell();
bcx = trans_expr(bcx, e, by_val(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}; return {bcx: bcx, val: *cell, kind: lv_temporary};
} else { } else {
let scratch = alloc_ty(bcx, ty); let scratch = alloc_ty(bcx, ty);
let bcx = trans_expr_save_in(bcx, e, scratch); 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}; return {bcx: bcx, val: scratch, kind: lv_temporary};
} }
} }
@ -5815,6 +5841,7 @@ fn trans_crate(sess: session::session,
module_data: str_hash::<ValueRef>(), module_data: str_hash::<ValueRef>(),
lltypes: ty::new_ty_hash(), lltypes: ty::new_ty_hash(),
names: new_namegen(sess.parse_sess.interner), names: new_namegen(sess.parse_sess.interner),
next_addrspace: new_addrspace_gen(),
symbol_hasher: symbol_hasher, symbol_hasher: symbol_hasher,
type_hashcodes: ty::new_ty_hash(), type_hashcodes: ty::new_ty_hash(),
type_short_names: ty::new_ty_hash(), type_short_names: ty::new_ty_hash(),

View File

@ -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 = type tydesc_info =
{ty: ty::t, {ty: ty::t,
tydesc: ValueRef, tydesc: ValueRef,
size: ValueRef, size: ValueRef,
align: ValueRef, align: ValueRef,
addrspace: addrspace,
mut take_glue: option<ValueRef>, mut take_glue: option<ValueRef>,
mut drop_glue: option<ValueRef>, mut drop_glue: option<ValueRef>,
mut free_glue: option<ValueRef>, mut free_glue: option<ValueRef>,
@ -118,6 +135,7 @@ type crate_ctxt = {
module_data: hashmap<~str, ValueRef>, module_data: hashmap<~str, ValueRef>,
lltypes: hashmap<ty::t, TypeRef>, lltypes: hashmap<ty::t, TypeRef>,
names: namegen, names: namegen,
next_addrspace: addrspace_gen,
symbol_hasher: @hash::State, symbol_hasher: @hash::State,
type_hashcodes: hashmap<ty::t, ~str>, type_hashcodes: hashmap<ty::t, ~str>,
type_short_names: 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) { // This is not the same as base::root_value, which appears to be the vestigial
if !ty::type_needs_drop(cx.tcx(), ty) { return; } // 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)", debug!("add_clean(%s, %s, %s)",
cx.to_str(), val_str(cx.ccx().tn, val), bcx.to_str(), val_str(bcx.ccx().tn, val),
ty_to_str(cx.ccx().tcx, ty)); ty_to_str(bcx.ccx().tcx, t));
let cleanup_type = cleanup_type(cx.tcx(), ty); let {root, rooted} = root_for_cleanup(bcx, val, t);
do in_scope_cx(cx) |info| { let cleanup_type = cleanup_type(bcx.tcx(), t);
vec::push(info.cleanups, clean(|a| base::drop_ty(a, val, ty), do in_scope_cx(bcx) |info| {
cleanup_type)); vec::push(info.cleanups,
clean(|a| base::drop_ty_root(a, root, rooted, t),
cleanup_type));
scope_clean_changed(info); 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; } if !ty::type_needs_drop(cx.tcx(), ty) { return; }
debug!("add_clean_temp(%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);
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)",
cx.to_str(), val_str(cx.ccx().tn, val), cx.to_str(), val_str(cx.ccx().tn, val),
ty_to_str(cx.ccx().tcx, ty)); ty_to_str(cx.ccx().tcx, ty));
let cleanup_type = cleanup_type(cx.tcx(), ty); let cleanup_type = cleanup_type(cx.tcx(), ty);
do in_scope_cx(cx) |info| { do in_scope_cx(cx) |info| {
vec::push(info.cleanups, 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)); cleanup_type));
scope_clean_changed(info); scope_clean_changed(info);
} }
@ -607,7 +642,11 @@ fn T_fn_pair(cx: @crate_ctxt, tfn: TypeRef) -> TypeRef {
} }
fn T_ptr(t: 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 { 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 { fn T_box_ptr(t: TypeRef) -> TypeRef {
const box_addrspace: uint = 1u; return llvm::LLVMPointerType(t, gc_box_addrspace);
return llvm::LLVMPointerType(t, box_addrspace as c_uint);
} }
fn T_opaque_box(cx: @crate_ctxt) -> TypeRef { 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 { fn T_unique_ptr(t: TypeRef) -> TypeRef {
const unique_addrspace: uint = 1u; return llvm::LLVMPointerType(t, gc_box_addrspace);
return llvm::LLVMPointerType(t, unique_addrspace as c_uint);
} }
fn T_port(cx: @crate_ctxt, _t: TypeRef) -> TypeRef { fn T_port(cx: @crate_ctxt, _t: TypeRef) -> TypeRef {

View File

@ -12,6 +12,7 @@ export type_of_fn_from_ty;
export type_of_fn; export type_of_fn;
export type_of_glue_fn; export type_of_glue_fn;
export type_of_non_gc_box; export type_of_non_gc_box;
export type_of_rooted;
fn type_of_explicit_args(cx: @crate_ctxt, fn type_of_explicit_args(cx: @crate_ctxt,
inputs: ~[ty::arg]) -> ~[TypeRef] { inputs: ~[ty::arg]) -> ~[TypeRef] {
@ -245,6 +246,13 @@ fn type_of_dtor(ccx: @crate_ctxt, self_ty: ty::t) -> TypeRef {
llvm::LLVMVoidType()) 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 { fn type_of_glue_fn(ccx: @crate_ctxt, t: ty::t) -> TypeRef {
let tydescpp = T_ptr(T_ptr(ccx.tydesc_type)); let tydescpp = T_ptr(T_ptr(ccx.tydesc_type));
let llty = T_ptr(type_of(ccx, t)); let llty = T_ptr(type_of(ccx, t));