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();
|
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));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -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(),
|
||||||
|
@ -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 {
|
||||||
|
@ -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));
|
||||||
|
Loading…
Reference in New Issue
Block a user