From c2e99ba8265085bde0a80283a68b4010a4a3aa34 Mon Sep 17 00:00:00 2001 From: Elliott Slaughter Date: Mon, 6 Aug 2012 10:53:38 -0700 Subject: [PATCH] rustc: Root resources with addrspaces. --- src/rustc/middle/trans/alt.rs | 2 +- src/rustc/middle/trans/base.rs | 33 ++++++++- src/rustc/middle/trans/common.rs | 109 ++++++++++++++++++++---------- src/rustc/middle/trans/type_of.rs | 8 +++ 4 files changed, 112 insertions(+), 40 deletions(-) diff --git a/src/rustc/middle/trans/alt.rs b/src/rustc/middle/trans/alt.rs index 9e45301d43a..af7c2dcb9ba 100644 --- a/src/rustc/middle/trans/alt.rs +++ b/src/rustc/middle/trans/alt.rs @@ -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)); } _ => { diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 13988ad8861..8aaf50dd52f 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -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::(), 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(), diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs index 47b427f3872..e397dd5c113 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -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, mut drop_glue: option, mut free_glue: option, @@ -118,6 +135,7 @@ type crate_ctxt = { module_data: hashmap<~str, ValueRef>, lltypes: hashmap, names: namegen, + next_addrspace: addrspace_gen, symbol_hasher: @hash::State, type_hashcodes: hashmap, type_short_names: hashmap, @@ -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 { diff --git a/src/rustc/middle/trans/type_of.rs b/src/rustc/middle/trans/type_of.rs index c5d7b5d7449..a7cde34fa4c 100644 --- a/src/rustc/middle/trans/type_of.rs +++ b/src/rustc/middle/trans/type_of.rs @@ -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));