about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorElliott Slaughter <eslaughter@mozilla.com>2012-08-06 10:53:38 -0700
committerElliott Slaughter <eslaughter@mozilla.com>2012-08-24 14:01:26 -0700
commitc2e99ba8265085bde0a80283a68b4010a4a3aa34 (patch)
treed70dc58d750726f2f51ab311c65626be281fccfe /src/rustc
parentc8daf2ac16b0f924011a0e1fc2be18abf020f5cd (diff)
rustc: Root resources with addrspaces.
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/trans/alt.rs2
-rw-r--r--src/rustc/middle/trans/base.rs33
-rw-r--r--src/rustc/middle/trans/common.rs101
-rw-r--r--src/rustc/middle/trans/type_of.rs8
4 files changed, 108 insertions, 36 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::<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(),
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<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)",
+    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));
+        vec::push(info.cleanups,
+                  clean_temp(val, |a| base::drop_ty_immediate(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; }
+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)",
-           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| {
+           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(a, val, ty),
+                  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));