about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-05-31 01:26:05 -0700
committerBrian Anderson <banderson@mozilla.com>2012-05-31 01:26:05 -0700
commit41b02b7c57092f1da63beec60358061a9579d8c6 (patch)
treeddf24839509ffcf50f6fc57c570b13a5b223ec87
parent615f5324754bdbb97998181cf1ada4c53337c7f3 (diff)
parent3a2c92b46334d422c438061335f6f76669c8743f (diff)
downloadrust-41b02b7c57092f1da63beec60358061a9579d8c6.tar.gz
rust-41b02b7c57092f1da63beec60358061a9579d8c6.zip
Merge remote-tracking branch 'brson/self-describing-uniques'
Conflicts:
	src/snapshots.txt
-rw-r--r--mk/host.mk2
-rw-r--r--mk/target.mk48
-rw-r--r--src/libcore/vec.rs7
-rw-r--r--src/rt/rust.cpp4
-rw-r--r--src/rt/rust_builtin.cpp63
-rw-r--r--src/rt/rust_cc.cpp8
-rw-r--r--src/rt/rust_shape.h30
-rw-r--r--src/rt/rust_task.cpp5
-rw-r--r--src/rt/rust_upcall.cpp200
-rw-r--r--src/rt/rust_upcall.h5
-rw-r--r--src/rt/rust_util.h42
-rw-r--r--src/rt/rustrt.def.in9
-rw-r--r--src/rustc/back/upcall.rs37
-rw-r--r--src/rustc/middle/trans/alt.rs9
-rw-r--r--src/rustc/middle/trans/base.rs91
-rw-r--r--src/rustc/middle/trans/closure.rs16
-rw-r--r--src/rustc/middle/trans/common.rs20
-rw-r--r--src/rustc/middle/trans/tvec.rs128
-rw-r--r--src/rustc/middle/trans/type_of.rs10
-rw-r--r--src/rustc/middle/trans/uniq.rs51
-rw-r--r--src/snapshots.txt8
21 files changed, 495 insertions, 298 deletions
diff --git a/mk/host.mk b/mk/host.mk
index 48d92011998..1065ac3f396 100644
--- a/mk/host.mk
+++ b/mk/host.mk
@@ -74,7 +74,7 @@ $$(HLIB$(2)_H_$(4))/$$(CFG_STDLIB): \
 	@$$(call E, cp: $$@)
 	$$(Q)cp $$< $$@
 	$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_GLOB) \
-		$$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_DSYM_GLOB) \
+		$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_DSYM_GLOB)) \
 	        $$(HLIB$(2)_H_$(4))
 
 $$(HLIB$(2)_H_$(4))/libcore.rlib: \
diff --git a/mk/target.mk b/mk/target.mk
index c049ce5c296..b6e00b978aa 100644
--- a/mk/target.mk
+++ b/mk/target.mk
@@ -8,8 +8,9 @@
 # (resp.  corelib), set this flag to 1.  It will cause stage1 to use
 # the snapshot runtime (resp. corelib) rather than the runtime
 # (resp. corelib) from the working directory.
-USE_SNAPSHOT_RUNTIME=0
-USE_SNAPSHOT_CORELIB=0
+USE_SNAPSHOT_RUNTIME=1
+USE_SNAPSHOT_CORELIB=1
+USE_SNAPSHOT_STDLIB=1
 
 define TARGET_STAGE_N
 
@@ -18,13 +19,6 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \
 	@$$(call E, cp: $$@)
 	$$(Q)cp $$< $$@
 
-$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_STDLIB): \
-		$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
-	        $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_CORELIB) \
-		$$(TSREQ$(1)_T_$(2)_H_$(3))
-	@$$(call E, compile_and_link: $$@)
-	$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
-
 $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUSTLLVM): \
 		rustllvm/$(2)/$$(CFG_RUSTLLVM)
 	@$$(call E, cp: $$@)
@@ -116,6 +110,30 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_CORELIB): \
 
 endef
 
+define TARGET_STDLIB_FROM_SNAPSHOT
+
+$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_STDLIB): \
+		$$(HLIB$(1)_H_$(3))/$$(CFG_STDLIB) \
+		$$(STDLIB_INPUTS) \
+		$$(TSREQ$(1)_T_$(2)_H_$(3))
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+	$$(Q)cp $$(HLIB$(1)_H_$(3))/$$(STDLIB_GLOB) \
+		$$(TLIB$(1)_T_$(2)_H_$(3))
+
+endef
+
+define TARGET_STDLIB_FROM_WD
+
+$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_STDLIB): \
+		$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
+	        $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_CORELIB) \
+		$$(TSREQ$(1)_T_$(2)_H_$(3))
+	@$$(call E, compile_and_link: $$@)
+	$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
+
+endef
+
 # In principle, each host can build each target:
 $(foreach source,$(CFG_TARGET_TRIPLES),				\
  $(foreach target,$(CFG_TARGET_TRIPLES),			\
@@ -142,11 +160,20 @@ else
 		$(eval $(call TARGET_CORELIB_FROM_WD,0,$(src),$(src))))
 endif
 
+ifeq ($(USE_SNAPSHOT_STDLIB),1)
+    $(foreach src,$(CFG_HOST_TRIPLE),\
+		$(eval $(call TARGET_STDLIB_FROM_SNAPSHOT,0,$(src),$(src))))
+else
+    $(foreach src,$(CFG_HOST_TRIPLE),\
+		$(eval $(call TARGET_STDLIB_FROM_WD,0,$(src),$(src))))
+endif
+
 # Non-host triples build the stage0 runtime from the working directory
 $(foreach source,$(CFG_TARGET_TRIPLES),				\
  $(foreach target,$(NON_HOST_TRIPLES),				\
   $(eval $(call TARGET_RT_FROM_WD,0,$(target),$(source)))       \
   $(eval $(call TARGET_CORELIB_FROM_WD,0,$(target),$(source)))  \
+  $(eval $(call TARGET_STDLIB_FROM_WD,0,$(target),$(source)))  \
 ))
 
 # After stage0, always build the stage0 runtime from the working directory
@@ -158,5 +185,8 @@ $(foreach source,$(CFG_TARGET_TRIPLES),				\
   $(eval $(call TARGET_CORELIB_FROM_WD,1,$(target),$(source)))	\
   $(eval $(call TARGET_CORELIB_FROM_WD,2,$(target),$(source)))	\
   $(eval $(call TARGET_CORELIB_FROM_WD,3,$(target),$(source)))	\
+  $(eval $(call TARGET_STDLIB_FROM_WD,1,$(target),$(source)))	\
+  $(eval $(call TARGET_STDLIB_FROM_WD,2,$(target),$(source)))	\
+  $(eval $(call TARGET_STDLIB_FROM_WD,3,$(target),$(source)))	\
 ))
 
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index fdc8b1ed248..a743cbc5576 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -1162,7 +1162,12 @@ impl extensions<T> for [T] {
 mod unsafe {
     // FIXME: This should have crate visibility (#1893 blocks that)
     #[doc = "The internal representation of a vector"]
-    type vec_repr = {mut fill: uint, mut alloc: uint, data: u8};
+    type vec_repr = {
+        box_header: (uint, uint, uint, uint),
+        mut fill: uint,
+        mut alloc: uint,
+        data: u8
+    };
 
     #[doc = "
     Constructs a vector from an unsafe pointer to a buffer
diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp
index 2fed06854cb..4019c8701ac 100644
--- a/src/rt/rust.cpp
+++ b/src/rt/rust.cpp
@@ -13,7 +13,7 @@ command_line_args : public kernel_owned<command_line_args>
     char **argv;
 
     // [str] passed to rust_task::start.
-    rust_vec *args;
+    rust_vec_box *args;
 
     command_line_args(rust_task *task,
                       int sys_argc,
@@ -47,7 +47,7 @@ command_line_args : public kernel_owned<command_line_args>
 
     ~command_line_args() {
         for (int i = 0; i < argc; ++i) {
-            rust_vec *s = ((rust_vec**)&args->data)[i];
+            rust_vec *s = ((rust_vec**)&args->body.data)[i];
             kernel->free(s);
         }
         kernel->free(args);
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index 97fbcf4953d..eebb114f5fc 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -85,7 +85,7 @@ rust_getcwd() {
 }
 
 #if defined(__WIN32__)
-extern "C" CDECL rust_vec *
+extern "C" CDECL rust_vec_box *
 rust_env_pairs() {
     rust_task *task = rust_get_current_task();
     size_t envc = 0;
@@ -95,14 +95,14 @@ rust_env_pairs() {
         ++envc;
     }
     c = ch;
-    rust_vec *v = (rust_vec *)
-        task->kernel->malloc(vec_size<rust_vec*>(envc),
+    rust_vec_box *v = (rust_vec_box *)
+        task->kernel->malloc(vec_size<rust_vec_box*>(envc),
                        "str vec interior");
-    v->fill = v->alloc = sizeof(rust_vec*) * envc;
+    v->body.fill = v->body.alloc = sizeof(rust_vec*) * envc;
     for (size_t i = 0; i < envc; ++i) {
         size_t n = strlen(c);
         rust_str *str = make_str(task->kernel, c, n, "str");
-        ((rust_str**)&v->data)[i] = str;
+        ((rust_str**)&v->body.data)[i] = str;
         c += n + 1;
     }
     if (ch) {
@@ -111,7 +111,7 @@ rust_env_pairs() {
     return v;
 }
 #else
-extern "C" CDECL rust_vec *
+extern "C" CDECL rust_vec_box *
 rust_env_pairs() {
     rust_task *task = rust_get_current_task();
 #ifdef __APPLE__
@@ -140,14 +140,14 @@ unsupervise() {
 }
 
 extern "C" CDECL void
-vec_reserve_shared(type_desc* ty, rust_vec** vp,
+vec_reserve_shared(type_desc* ty, rust_vec_box** vp,
                    size_t n_elts) {
     rust_task *task = rust_get_current_task();
     reserve_vec_exact(task, vp, n_elts * ty->size);
 }
 
 extern "C" CDECL void
-str_reserve_shared(rust_vec** sp,
+str_reserve_shared(rust_vec_box** sp,
                    size_t n_elts) {
     rust_task *task = rust_get_current_task();
     reserve_vec_exact(task, sp, n_elts + 1);
@@ -157,25 +157,26 @@ str_reserve_shared(rust_vec** sp,
  * Copies elements in an unsafe buffer to the given interior vector. The
  * vector must have size zero.
  */
-extern "C" CDECL rust_vec*
+extern "C" CDECL rust_vec_box*
 vec_from_buf_shared(type_desc *ty, void *ptr, size_t count) {
     rust_task *task = rust_get_current_task();
     size_t fill = ty->size * count;
-    rust_vec* v = (rust_vec*)task->kernel->malloc(fill + sizeof(rust_vec),
-                                                    "vec_from_buf");
-    v->fill = v->alloc = fill;
-    memmove(&v->data[0], ptr, fill);
+    rust_vec_box* v = (rust_vec_box*)
+        task->kernel->malloc(fill + sizeof(rust_vec_box),
+                             "vec_from_buf");
+    v->body.fill = v->body.alloc = fill;
+    memmove(&v->body.data[0], ptr, fill);
     return v;
 }
 
 extern "C" CDECL void
-rust_str_push(rust_vec** sp, uint8_t byte) {
+rust_str_push(rust_vec_box** sp, uint8_t byte) {
     rust_task *task = rust_get_current_task();
-    size_t fill = (*sp)->fill;
+    size_t fill = (*sp)->body.fill;
     reserve_vec(task, sp, fill + 1);
-    (*sp)->data[fill-1] = byte;
-    (*sp)->data[fill] = 0;
-    (*sp)->fill = fill + 1;
+    (*sp)->body.data[fill-1] = byte;
+    (*sp)->body.data[fill] = 0;
+    (*sp)->body.fill = fill + 1;
 }
 
 extern "C" CDECL rust_vec*
@@ -367,13 +368,13 @@ debug_get_stk_seg() {
     return task->stk;
 }
 
-extern "C" CDECL rust_vec*
+extern "C" CDECL rust_vec_box*
 rust_list_files(rust_str *path) {
     rust_task *task = rust_get_current_task();
     array_list<rust_str*> strings;
 #if defined(__WIN32__)
     WIN32_FIND_DATA FindFileData;
-    HANDLE hFind = FindFirstFile((char*)path->data, &FindFileData);
+    HANDLE hFind = FindFirstFile((char*)path->body.data, &FindFileData);
     if (hFind != INVALID_HANDLE_VALUE) {
         do {
             rust_str *str = make_str(task->kernel, FindFileData.cFileName,
@@ -384,25 +385,25 @@ rust_list_files(rust_str *path) {
         FindClose(hFind);
     }
 #else
-    DIR *dirp = opendir((char*)path->data);
+    DIR *dirp = opendir((char*)path->body.data);
   if (dirp) {
       struct dirent *dp;
       while ((dp = readdir(dirp))) {
-          rust_vec *str = make_str(task->kernel, dp->d_name,
-                                    strlen(dp->d_name),
-                                    "list_files_str");
+          rust_vec_box *str = make_str(task->kernel, dp->d_name,
+                                       strlen(dp->d_name),
+                                       "list_files_str");
           strings.push(str);
       }
       closedir(dirp);
   }
 #endif
 
-  rust_vec *vec = (rust_vec *)
-      task->kernel->malloc(vec_size<rust_vec*>(strings.size()),
+  rust_vec_box *vec = (rust_vec_box *)
+      task->kernel->malloc(vec_size<rust_vec_box*>(strings.size()),
                            "list_files_vec");
   size_t alloc_sz = sizeof(rust_vec*) * strings.size();
-  vec->fill = vec->alloc = alloc_sz;
-  memcpy(&vec->data[0], strings.data(), alloc_sz);
+  vec->body.fill = vec->body.alloc = alloc_sz;
+  memcpy(&vec->body.data[0], strings.data(), alloc_sz);
   return vec;
 }
 
@@ -520,9 +521,9 @@ void tm_to_rust_tm(tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
     if (zone != NULL) {
         size_t size = strlen(zone);
         str_reserve_shared(&out_tm->tm_zone, size);
-        memcpy(out_tm->tm_zone->data, zone, size);
-        out_tm->tm_zone->fill = size + 1;
-        out_tm->tm_zone->data[size] = '\0';
+        memcpy(out_tm->tm_zone->body.data, zone, size);
+        out_tm->tm_zone->body.fill = size + 1;
+        out_tm->tm_zone->body.data[size] = '\0';
     }
 }
 
diff --git a/src/rt/rust_cc.cpp b/src/rt/rust_cc.cpp
index 66f044b8ce9..4d6aaf02070 100644
--- a/src/rt/rust_cc.cpp
+++ b/src/rt/rust_cc.cpp
@@ -117,7 +117,9 @@ class irc : public shape::data<irc,shape::ptr> {
     }
 
     void walk_uniq2() {
-        shape::data<irc,shape::ptr>::walk_uniq_contents1();
+        rust_opaque_box *box = *(rust_opaque_box**)dp;
+        if (box)
+            shape::data<irc,shape::ptr>::walk_uniq_contents1();
     }
 
     void walk_rptr2() {
@@ -373,7 +375,9 @@ class mark : public shape::data<mark,shape::ptr> {
     }
 
     void walk_uniq2() {
-        shape::data<mark,shape::ptr>::walk_uniq_contents1();
+        rust_opaque_box *box = *(rust_opaque_box**)dp;
+        if (box)
+            shape::data<mark,shape::ptr>::walk_uniq_contents1();
     }
 
     void walk_rptr2() {
diff --git a/src/rt/rust_shape.h b/src/rt/rust_shape.h
index c6817b23a6e..77a253d2bb7 100644
--- a/src/rt/rust_shape.h
+++ b/src/rt/rust_shape.h
@@ -783,6 +783,11 @@ public:
         return box->td;
     }
 
+    inline const type_desc *uniq_body_td() const {
+        rust_opaque_box *box = *reinterpret_cast<rust_opaque_box**>(p);
+        return box->td;
+    }
+
     inline ptr box_body() const {
         rust_opaque_box *box = *reinterpret_cast<rust_opaque_box**>(p);
         return make((uint8_t*)::box_body(box));
@@ -881,6 +886,11 @@ public:
         return box_fst->td;
     }
 
+    inline const type_desc *uniq_body_td() const {
+        rust_opaque_box *box_fst = *reinterpret_cast<rust_opaque_box**>(fst);
+        return box_fst->td;
+    }
+
     inline ptr_pair box_body() const {
         rust_opaque_box *box_fst = *reinterpret_cast<rust_opaque_box**>(fst);
         rust_opaque_box *box_snd = *reinterpret_cast<rust_opaque_box**>(snd);
@@ -1067,10 +1077,16 @@ data<T,U>::walk_box_contents1() {
 template<typename T,typename U>
 void
 data<T,U>::walk_uniq_contents1() {
-    typename U::template data<uint8_t *>::t box_ptr = bump_dp<uint8_t *>(dp);
-    U data_ptr(box_ptr);
-    T sub(*static_cast<T *>(this), data_ptr);
-    static_cast<T *>(this)->walk_uniq_contents2(sub);
+    const type_desc *body_td = dp.uniq_body_td();
+    if (body_td) {
+        U body_dp(dp.box_body());
+        arena arena;
+        type_param *params = type_param::from_tydesc(body_td, arena);
+        T sub(*static_cast<T *>(this), body_td->shape, params,
+              body_td->shape_tables, body_dp);
+        sub.align = true;
+        static_cast<T *>(this)->walk_uniq_contents2(sub);
+    }
 }
 
 template<typename T,typename U>
@@ -1094,9 +1110,9 @@ data<T,U>::walk_variant1(tag_info &tinfo, tag_variant_t variant_id) {
 template<typename T,typename U>
 std::pair<uint8_t *,uint8_t *>
 data<T,U>::get_vec_data_range(ptr dp) {
-    rust_vec* ptr = bump_dp<rust_vec*>(dp);
-    uint8_t* data = &ptr->data[0];
-    return std::make_pair(data, data + ptr->fill);
+    rust_vec_box* ptr = bump_dp<rust_vec_box*>(dp);
+    uint8_t* data = &ptr->body.data[0];
+    return std::make_pair(data, data + ptr->body.fill);
 }
 
 template<typename T,typename U>
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 2331cccd590..5299de0ed34 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -7,7 +7,6 @@
 
 #include "rust_task.h"
 #include "rust_cc.h"
-#include "rust_upcall.h"
 #include "rust_env.h"
 #include "rust_port.h"
 
@@ -130,6 +129,8 @@ cleanup_task(cleanup_args *args) {
     }
 }
 
+extern "C" CDECL void upcall_exchange_free(void *ptr);
+
 // This runs on the Rust stack
 void task_start_wrapper(spawn_args *a)
 {
@@ -161,7 +162,7 @@ void task_start_wrapper(spawn_args *a)
         // free the environment (which should be a unique closure).
         const type_desc *td = env->td;
         td->drop_glue(NULL, NULL, td->first_param, box_body(env));
-        upcall_shared_free(env);
+        upcall_exchange_free(env);
     }
 
     // The cleanup work needs lots of stack
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 9ad1f3a5e4d..ac11ee7a26b 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -152,6 +152,92 @@ upcall_trace(char const *msg,
 }
 
 /**********************************************************************
+ * Allocate an object in the exchange heap
+ */
+
+extern "C" CDECL uintptr_t
+exchange_malloc(rust_task *task, type_desc *td, uintptr_t size) {
+
+    LOG(task, mem, "upcall exchange malloc(0x%" PRIxPTR ")", td);
+
+    // Copied from boxed_region
+    size_t header_size = sizeof(rust_opaque_box);
+    size_t body_size = size;
+    size_t body_align = td->align;
+    // FIXME: This alignment calculation is suspicious. Is it right?
+    size_t total_size = align_to(header_size, body_align) + body_size;
+
+    void *p = task->kernel->malloc(total_size, "exchange malloc");
+
+    rust_opaque_box *header = static_cast<rust_opaque_box*>(p);
+    header->td = td;
+
+    memset(&header[1], '\0', body_size);
+
+    return (uintptr_t)header;
+}
+
+struct s_exchange_malloc_args {
+    uintptr_t retval;
+    type_desc *td;
+};
+
+extern "C" CDECL void
+upcall_s_exchange_malloc(s_exchange_malloc_args *args) {
+    rust_task *task = rust_get_current_task();
+    LOG_UPCALL_ENTRY(task);
+
+    uintptr_t retval = exchange_malloc(task, args->td, args->td->size);
+    args->retval = retval;
+}
+
+extern "C" CDECL uintptr_t
+upcall_exchange_malloc(type_desc *td) {
+    s_exchange_malloc_args args = {0, td};
+    UPCALL_SWITCH_STACK(&args, upcall_s_exchange_malloc);
+    return args.retval;
+}
+
+struct s_exchange_malloc_dyn_args {
+    uintptr_t retval;
+    type_desc *td;
+    uintptr_t size;
+};
+
+extern "C" CDECL void
+upcall_s_exchange_malloc_dyn(s_exchange_malloc_dyn_args *args) {
+    rust_task *task = rust_get_current_task();
+    LOG_UPCALL_ENTRY(task);
+
+    uintptr_t retval = exchange_malloc(task, args->td, args->size);
+    args->retval = retval;
+}
+
+extern "C" CDECL uintptr_t
+upcall_exchange_malloc_dyn(type_desc *td, uintptr_t size) {
+    s_exchange_malloc_dyn_args args = {0, td, size};
+    UPCALL_SWITCH_STACK(&args, upcall_s_exchange_malloc_dyn);
+    return args.retval;
+}
+
+struct s_exchange_free_args {
+    void *ptr;
+};
+
+extern "C" CDECL void
+upcall_s_exchange_free(s_exchange_free_args *args) {
+    rust_task *task = rust_get_current_task();
+    LOG_UPCALL_ENTRY(task);
+    task->kernel->free(args->ptr);
+}
+
+extern "C" CDECL void
+upcall_exchange_free(void *ptr) {
+    s_exchange_free_args args = {ptr};
+    UPCALL_SWITCH_STACK(&args, upcall_s_exchange_free);
+}
+
+/**********************************************************************
  * Allocate an object in the task-local heap.
  */
 
@@ -234,81 +320,6 @@ upcall_validate_box(rust_opaque_box* ptr) {
     }
 }
 
-/**********************************************************************
- * Allocate an object in the exchange heap.
- */
-
-struct s_shared_malloc_args {
-    uintptr_t retval;
-    size_t nbytes;
-};
-
-extern "C" CDECL void
-upcall_s_shared_malloc(s_shared_malloc_args *args) {
-    rust_task *task = rust_get_current_task();
-    LOG_UPCALL_ENTRY(task);
-
-    LOG(task, mem, "upcall shared_malloc(%" PRIdPTR ")", args->nbytes);
-    void *p = task->kernel->malloc(args->nbytes, "shared malloc");
-    memset(p, '\0', args->nbytes);
-    LOG(task, mem, "upcall shared_malloc(%" PRIdPTR ") = 0x%" PRIxPTR,
-        args->nbytes, (uintptr_t)p);
-    args->retval = (uintptr_t) p;
-}
-
-extern "C" CDECL uintptr_t
-upcall_shared_malloc(size_t nbytes) {
-    s_shared_malloc_args args = {0, nbytes};
-    UPCALL_SWITCH_STACK(&args, upcall_s_shared_malloc);
-    return args.retval;
-}
-
-/**********************************************************************
- * Called whenever an object in the exchange heap is freed.
- */
-
-struct s_shared_free_args {
-    void *ptr;
-};
-
-extern "C" CDECL void
-upcall_s_shared_free(s_shared_free_args *args) {
-    rust_task *task = rust_get_current_task();
-    LOG_UPCALL_ENTRY(task);
-
-    rust_sched_loop *sched_loop = task->sched_loop;
-    DLOG(sched_loop, mem,
-             "upcall shared_free(0x%" PRIxPTR")",
-             (uintptr_t)args->ptr);
-    task->kernel->free(args->ptr);
-}
-
-extern "C" CDECL void
-upcall_shared_free(void* ptr) {
-    s_shared_free_args args = {ptr};
-    UPCALL_SWITCH_STACK(&args, upcall_s_shared_free);
-}
-
-struct s_shared_realloc_args {
-    void *retval;
-    void *ptr;
-    size_t size;
-};
-
-extern "C" CDECL void
-upcall_s_shared_realloc(s_shared_realloc_args *args) {
-    rust_task *task = rust_get_current_task();
-    LOG_UPCALL_ENTRY(task);
-    args->retval = task->kernel->realloc(args->ptr, args->size);
-}
-
-extern "C" CDECL void *
-upcall_shared_realloc(void *ptr, size_t size) {
-    s_shared_realloc_args args = {NULL, ptr, size};
-    UPCALL_SWITCH_STACK(&args, upcall_s_shared_realloc);
-    return args.retval;
-}
-
 /**********************************************************************/
 
 struct s_str_new_uniq_args {
@@ -361,10 +372,10 @@ upcall_s_str_new_shared(s_str_new_shared_args *args) {
                              vec_size<char>(str_fill),
                              "str_new_shared");
     rust_str *str = (rust_str *)box_body(args->retval);
-    str->fill = str_fill;
-    str->alloc = str_alloc;
-    memcpy(&str->data, args->cstr, args->len);
-    str->data[args->len] = '\0';
+    str->body.fill = str_fill;
+    str->body.alloc = str_alloc;
+    memcpy(&str->body.data, args->cstr, args->len);
+    str->body.data[args->len] = '\0';
 }
 
 extern "C" CDECL rust_opaque_box*
@@ -376,7 +387,7 @@ upcall_str_new_shared(const char *cstr, size_t len) {
 
 
 struct s_vec_grow_args {
-    rust_vec** vp;
+    rust_vec_box** vp;
     size_t new_sz;
 };
 
@@ -385,37 +396,38 @@ upcall_s_vec_grow(s_vec_grow_args *args) {
     rust_task *task = rust_get_current_task();
     LOG_UPCALL_ENTRY(task);
     reserve_vec(task, args->vp, args->new_sz);
-    (*args->vp)->fill = args->new_sz;
+    (*args->vp)->body.fill = args->new_sz;
 }
 
 extern "C" CDECL void
-upcall_vec_grow(rust_vec** vp, size_t new_sz) {
+upcall_vec_grow(rust_vec_box** vp, size_t new_sz) {
     s_vec_grow_args args = {vp, new_sz};
     UPCALL_SWITCH_STACK(&args, upcall_s_vec_grow);
 }
 
 struct s_str_concat_args {
-    rust_vec* lhs;
-    rust_vec* rhs;
-    rust_vec* retval;
+    rust_vec_box* lhs;
+    rust_vec_box* rhs;
+    rust_vec_box* retval;
 };
 
 extern "C" CDECL void
 upcall_s_str_concat(s_str_concat_args *args) {
-    rust_vec *lhs = args->lhs;
-    rust_vec *rhs = args->rhs;
+    rust_vec *lhs = &args->lhs->body;
+    rust_vec *rhs = &args->rhs->body;
     rust_task *task = rust_get_current_task();
     size_t fill = lhs->fill + rhs->fill - 1;
-    rust_vec* v = (rust_vec*)task->kernel->malloc(fill + sizeof(rust_vec),
-                                                  "str_concat");
-    v->fill = v->alloc = fill;
-    memmove(&v->data[0], &lhs->data[0], lhs->fill - 1);
-    memmove(&v->data[lhs->fill - 1], &rhs->data[0], rhs->fill);
+    rust_vec_box* v = (rust_vec_box*)
+        task->kernel->malloc(fill + sizeof(rust_vec_box),
+                             "str_concat");
+    v->body.fill = v->body.alloc = fill;
+    memmove(&v->body.data[0], &lhs->data[0], lhs->fill - 1);
+    memmove(&v->body.data[lhs->fill - 1], &rhs->data[0], rhs->fill);
     args->retval = v;
 }
 
-extern "C" CDECL rust_vec*
-upcall_str_concat(rust_vec* lhs, rust_vec* rhs) {
+extern "C" CDECL rust_vec_box*
+upcall_str_concat(rust_vec_box* lhs, rust_vec_box* rhs) {
     s_str_concat_args args = {lhs, rhs, 0};
     UPCALL_SWITCH_STACK(&args, upcall_s_str_concat);
     return args.retval;
diff --git a/src/rt/rust_upcall.h b/src/rt/rust_upcall.h
index 0030ef19b36..b2b2db20674 100644
--- a/src/rt/rust_upcall.h
+++ b/src/rt/rust_upcall.h
@@ -1,9 +1,4 @@
-
 #ifndef RUST_UPCALL_H
 #define RUST_UPCALL_H
 
-// Upcalls used from C code on occasion:
-
-extern "C" CDECL void upcall_shared_free(void* ptr);
-
 #endif
diff --git a/src/rt/rust_util.h b/src/rt/rust_util.h
index b517362df1f..3a7bd0b7d71 100644
--- a/src/rt/rust_util.h
+++ b/src/rt/rust_util.h
@@ -42,9 +42,16 @@ rust_vec
     uint8_t data[0];
 };
 
+struct
+rust_vec_box
+{
+    rust_opaque_box header;
+    rust_vec body;
+};
+
 template <typename T>
 inline size_t vec_size(size_t elems) {
-    return sizeof(rust_vec) + sizeof(T) * elems;
+    return sizeof(rust_vec_box) + sizeof(T) * elems;
 }
 
 template <typename T>
@@ -53,19 +60,20 @@ vec_data(rust_vec *v) {
     return reinterpret_cast<T*>(v->data);
 }
 
-inline void reserve_vec_exact(rust_task* task, rust_vec** vpp, size_t size) {
-    if (size > (*vpp)->alloc) {
-        *vpp = (rust_vec*)task->kernel
-            ->realloc(*vpp, size + sizeof(rust_vec));
-        (*vpp)->alloc = size;
+inline void reserve_vec_exact(rust_task* task, rust_vec_box** vpp,
+                              size_t size) {
+    if (size > (*vpp)->body.alloc) {
+        *vpp = (rust_vec_box*)task->kernel
+            ->realloc(*vpp, size + sizeof(rust_vec_box));
+        (*vpp)->body.alloc = size;
     }
 }
 
-inline void reserve_vec(rust_task* task, rust_vec** vpp, size_t size) {
+inline void reserve_vec(rust_task* task, rust_vec_box** vpp, size_t size) {
     reserve_vec_exact(task, vpp, next_power_of_two(size));
 }
 
-typedef rust_vec rust_str;
+typedef rust_vec_box rust_str;
 
 inline rust_str *
 make_str(rust_kernel* kernel, const char* c, size_t strlen,
@@ -74,24 +82,24 @@ make_str(rust_kernel* kernel, const char* c, size_t strlen,
     size_t str_alloc = str_fill;
     rust_str *str = (rust_str *)
         kernel->malloc(vec_size<char>(str_fill), name);
-    str->fill = str_fill;
-    str->alloc = str_alloc;
-    memcpy(&str->data, c, strlen);
-    str->data[strlen] = '\0';
+    str->body.fill = str_fill;
+    str->body.alloc = str_alloc;
+    memcpy(&str->body.data, c, strlen);
+    str->body.data[strlen] = '\0';
     return str;
 }
 
-inline rust_vec *
+inline rust_vec_box *
 make_str_vec(rust_kernel* kernel, size_t nstrs, char **strs) {
-    rust_vec *v = (rust_vec *)
-        kernel->malloc(vec_size<rust_vec*>(nstrs),
+    rust_vec_box *v = (rust_vec_box *)
+        kernel->malloc(vec_size<rust_vec_box*>(nstrs),
                        "str vec interior");
-    v->fill = v->alloc = sizeof(rust_vec*) * nstrs;
+    v->body.fill = v->body.alloc = sizeof(rust_vec_box*) * nstrs;
     for (size_t i = 0; i < nstrs; ++i) {
         rust_str *str = make_str(kernel, strs[i],
                                  strlen(strs[i]),
                                  "str");
-        ((rust_str**)&v->data)[i] = str;
+        ((rust_str**)&v->body.data)[i] = str;
     }
     return v;
 }
diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in
index d982110bb99..8a627795850 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -74,10 +74,6 @@ upcall_validate_box
 upcall_log_type
 upcall_malloc
 upcall_rust_personality
-upcall_s_shared_malloc
-upcall_shared_malloc
-upcall_shared_free
-upcall_shared_realloc
 upcall_vec_grow
 upcall_str_new
 upcall_str_new_uniq
@@ -88,6 +84,9 @@ upcall_call_shim_on_rust_stack
 upcall_new_stack
 upcall_del_stack
 upcall_reset_stack_limit
+upcall_exchange_malloc
+upcall_exchange_malloc_dyn
+upcall_exchange_free
 rust_uv_loop_new
 rust_uv_loop_delete
 rust_uv_loop_refcount
@@ -161,4 +160,4 @@ rust_port_take
 rust_port_drop
 rust_port_task
 rust_task_inhibit_kill
-rust_task_allow_kill
\ No newline at end of file
+rust_task_allow_kill
diff --git a/src/rustc/back/upcall.rs b/src/rustc/back/upcall.rs
index 7cc71fca0b2..33fec5fab03 100644
--- a/src/rustc/back/upcall.rs
+++ b/src/rustc/back/upcall.rs
@@ -3,8 +3,8 @@ import driver::session;
 import middle::trans::base;
 import middle::trans::common::{T_fn, T_i1, T_i8, T_i32,
                                T_int, T_nil,
-                               T_opaque_vec, T_ptr,
-                               T_size_t, T_void};
+                               T_opaque_vec, T_ptr, T_unique_ptr,
+                               T_size_t, T_void, T_vec2};
 import lib::llvm::{type_names, ModuleRef, ValueRef, TypeRef};
 
 type upcalls =
@@ -12,10 +12,10 @@ type upcalls =
      trace: ValueRef,
      malloc: ValueRef,
      free: ValueRef,
+     exchange_malloc: ValueRef,
+     exchange_malloc_dyn: ValueRef,
+     exchange_free: ValueRef,
      validate_box: ValueRef,
-     shared_malloc: ValueRef,
-     shared_free: ValueRef,
-     shared_realloc: ValueRef,
      mark: ValueRef,
      vec_grow: ValueRef,
      str_new_uniq: ValueRef,
@@ -49,7 +49,6 @@ fn declare_upcalls(targ_cfg: @session::config,
 
     let int_t = T_int(targ_cfg);
     let size_t = T_size_t(targ_cfg);
-    let opaque_vec_t = T_opaque_vec(targ_cfg);
 
     ret @{_fail: dv("fail", [T_ptr(T_i8()),
                              T_ptr(T_i8()),
@@ -62,29 +61,31 @@ fn declare_upcalls(targ_cfg: @session::config,
                         T_ptr(T_i8()))),
           free:
               nothrow(dv("free", [T_ptr(T_i8())])),
+          exchange_malloc:
+              nothrow(d("exchange_malloc", [T_ptr(tydesc_type)],
+                        T_ptr(T_i8()))),
+          exchange_malloc_dyn:
+              nothrow(d("exchange_malloc_dyn",
+                        [T_ptr(tydesc_type), int_t],
+                        T_ptr(T_i8()))),
+          exchange_free:
+              nothrow(dv("exchange_free", [T_ptr(T_i8())])),
           validate_box:
               nothrow(dv("validate_box", [T_ptr(T_i8())])),
-          shared_malloc:
-              nothrow(d("shared_malloc", [size_t], T_ptr(T_i8()))),
-          shared_free:
-              nothrow(dv("shared_free", [T_ptr(T_i8())])),
-          shared_realloc:
-              nothrow(d("shared_realloc", [T_ptr(T_i8()), size_t],
-                        T_ptr(T_i8()))),
           mark:
               d("mark", [T_ptr(T_i8())], int_t),
           vec_grow:
-              nothrow(dv("vec_grow", [T_ptr(T_ptr(opaque_vec_t)), int_t])),
+              nothrow(dv("vec_grow", [T_ptr(T_ptr(T_i8())), int_t])),
           str_new_uniq:
               nothrow(d("str_new_uniq", [T_ptr(T_i8()), int_t],
-                        T_ptr(opaque_vec_t))),
+                        T_ptr(T_i8()))),
           str_new_shared:
               nothrow(d("str_new_shared", [T_ptr(T_i8()), int_t],
                         T_ptr(T_i8()))),
           str_concat:
-              nothrow(d("str_concat", [T_ptr(opaque_vec_t),
-                                       T_ptr(opaque_vec_t)],
-                        T_ptr(opaque_vec_t))),
+              nothrow(d("str_concat", [T_ptr(T_i8()),
+                                       T_ptr(T_i8())],
+                        T_ptr(T_i8()))),
           cmp_type:
               dv("cmp_type",
                  [T_ptr(T_i1()), T_ptr(tydesc_type),
diff --git a/src/rustc/middle/trans/alt.rs b/src/rustc/middle/trans/alt.rs
index 3cac9f3685e..5c079f30106 100644
--- a/src/rustc/middle/trans/alt.rs
+++ b/src/rustc/middle/trans/alt.rs
@@ -471,7 +471,8 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef],
     }
 
     if any_uniq_pat(m, col) {
-        let unboxed = Load(bcx, val);
+        let box = Load(bcx, val);
+        let unboxed = GEPi(bcx, box, [0u, abi::box_field_body]);
         compile_submatch(bcx, enter_uniq(dm, m, col, val),
                          [unboxed] + vals_left, chk, exits);
         ret;
@@ -762,8 +763,10 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
         bcx = bind_irrefutable_pat(bcx, inner, unboxed, true);
       }
       ast::pat_uniq(inner) {
-        let val = Load(bcx, val);
-        bcx = bind_irrefutable_pat(bcx, inner, val, true);
+        let box = Load(bcx, val);
+        let unboxed =
+            GEPi(bcx, box, [0u, abi::box_field_body]);
+        bcx = bind_irrefutable_pat(bcx, inner, unboxed, true);
       }
       ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) { }
     }
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 1dee76c61ed..a95797fd7e3 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -236,9 +236,9 @@ fn trans_free(cx: block, v: ValueRef) -> block {
     cx
 }
 
-fn trans_shared_free(cx: block, v: ValueRef) -> block {
+fn trans_unique_free(cx: block, v: ValueRef) -> block {
     let _icx = cx.insn_ctxt("trans_shared_free");
-    Call(cx, cx.ccx().upcalls.shared_free,
+    Call(cx, cx.ccx().upcalls.exchange_free,
          [PointerCast(cx, v, T_ptr(T_i8()))]);
     ret cx;
 }
@@ -326,15 +326,6 @@ fn GEP_enum(bcx: block, llblobptr: ValueRef, enum_id: ast::def_id,
     GEPi(bcx, typed_blobptr, [0u, ix])
 }
 
-// trans_shared_malloc: expects a type indicating which pointer type we want
-// and a size indicating how much space we want malloc'd.
-fn shared_malloc(cx: block, llptr_ty: TypeRef, llsize: ValueRef)
-   -> ValueRef {
-    let _icx = cx.insn_ctxt("opaque_shared_malloc");
-    let rval = Call(cx, cx.ccx().upcalls.shared_malloc, [llsize]);
-    PointerCast(cx, rval, llptr_ty)
-}
-
 // Returns a pointer to the body for the box. The box may be an opaque
 // box. The result will be casted to the type of body_t, if it is statically
 // known.
@@ -384,6 +375,59 @@ fn malloc_boxed(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} {
     ret {box: box, body: body};
 }
 
+fn malloc_unique_raw(bcx: block, t: ty::t) -> ValueRef {
+    let _icx = bcx.insn_ctxt("malloc_unique_box_raw");
+    let ccx = bcx.ccx();
+
+    // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
+    // wants.
+    let box_ptr = ty::mk_imm_uniq(ccx.tcx, t);
+    let llty = type_of(ccx, box_ptr);
+
+    // Get the tydesc for the body:
+    let mut static_ti = none;
+    let lltydesc = get_tydesc(ccx, t, static_ti);
+    lazily_emit_all_tydesc_glue(ccx, static_ti);
+
+    // Allocate space:
+    let rval = Call(bcx, ccx.upcalls.exchange_malloc, [lltydesc]);
+    ret PointerCast(bcx, rval, llty);
+}
+
+fn malloc_unique(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} {
+    let _icx = bcx.insn_ctxt("malloc_unique_box");
+    let box = malloc_unique_raw(bcx, t);
+    let body = GEPi(bcx, box, [0u, abi::box_field_body]);
+    ret {box: box, body: body};
+}
+
+fn malloc_unique_dyn_raw(bcx: block, t: ty::t, size: ValueRef) -> ValueRef {
+    let _icx = bcx.insn_ctxt("malloc_unique_box_raw");
+    let ccx = bcx.ccx();
+
+    // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
+    // wants.
+    let box_ptr = ty::mk_imm_uniq(ccx.tcx, t);
+    let llty = type_of(ccx, box_ptr);
+
+    // Get the tydesc for the body:
+    let mut static_ti = none;
+    let lltydesc = get_tydesc(ccx, t, static_ti);
+    lazily_emit_all_tydesc_glue(ccx, static_ti);
+
+    // Allocate space:
+    let rval = Call(bcx, ccx.upcalls.exchange_malloc_dyn, [lltydesc, size]);
+    ret PointerCast(bcx, rval, llty);
+}
+
+fn malloc_unique_dyn(bcx: block, t: ty::t, size: ValueRef
+                    ) -> {box: ValueRef, body: ValueRef} {
+    let _icx = bcx.insn_ctxt("malloc_unique_box");
+    let box = malloc_unique_dyn_raw(bcx, t, size);
+    let body = GEPi(bcx, box, [0u, abi::box_field_body]);
+    ret {box: box, body: body};
+}
+
 // Type descriptor and type glue stuff
 
 fn get_tydesc_simple(ccx: @crate_ctxt, t: ty::t) -> ValueRef {
@@ -1754,7 +1798,7 @@ fn autoderef(cx: block, e_id: ast::node_id,
             v1 = PointerCast(cx, body, T_ptr(llty));
           }
           ty::ty_uniq(_) {
-            let derefed = uniq::autoderef(v1, t1);
+            let derefed = uniq::autoderef(cx, v1, t1);
             t1 = derefed.t;
             v1 = derefed.v;
           }
@@ -2636,6 +2680,9 @@ fn trans_lval(cx: block, e: @ast::expr) -> lval_result {
                 let non_gc_val = non_gc_box_cast(sub.bcx, sub.val, t);
                 GEPi(sub.bcx, non_gc_val, [0u, abi::box_field_body])
               }
+              ty::ty_uniq(_) {
+                GEPi(sub.bcx, sub.val, [0u, abi::box_field_body])
+              }
               ty::ty_res(_, _, _) {
                 GEPi(sub.bcx, sub.val, [0u, 1u])
               }
@@ -2644,7 +2691,7 @@ fn trans_lval(cx: block, e: @ast::expr) -> lval_result {
                 let ellty = T_ptr(type_of(ccx, ety));
                 PointerCast(sub.bcx, sub.val, ellty)
               }
-              ty::ty_ptr(_) | ty::ty_uniq(_) | ty::ty_rptr(_,_) { sub.val }
+              ty::ty_ptr(_) | ty::ty_rptr(_,_) { sub.val }
             };
             ret lval_owned(sub.bcx, val);
           }
@@ -2920,7 +2967,15 @@ fn adapt_borrowed_value(lv: lval_result, _arg: ty::arg,
       }
 
       ty::ty_uniq(_) {
-        ret lv; // no change needed at runtime (I think)
+        let box_ptr = {
+            alt lv.kind {
+              temporary { lv.val }
+              owned { Load(bcx, lv.val) }
+              owned_imm { lv.val }
+            }
+        };
+        let body_ptr = GEPi(bcx, box_ptr, [0u, abi::box_field_body]);
+        ret lval_temp(bcx, body_ptr);
       }
 
       ty::ty_str | ty::ty_vec(_) |
@@ -3817,9 +3872,11 @@ fn trans_fail_expr(bcx: block, sp_opt: option<span>,
         bcx = expr_res.bcx;
 
         if ty::type_is_str(e_ty) {
-            let data = tvec::get_dataptr(
-                bcx, expr_res.val, type_of(
-                    ccx, ty::mk_mach_uint(tcx, ast::ty_u8)));
+            let unit_ty = ty::mk_mach_uint(tcx, ast::ty_u8);
+            let vec_ty = ty::mk_vec(tcx, {ty: unit_ty, mutbl: ast::m_imm});
+            let unit_llty = type_of(ccx, unit_ty);
+            let body = tvec::get_bodyptr(bcx, expr_res.val, vec_ty);
+            let data = tvec::get_dataptr(bcx, body, unit_llty);
             ret trans_fail_value(bcx, sp_opt, data);
         } else if bcx.unreachable || ty::type_is_bot(e_ty) {
             ret bcx;
diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs
index 7f58053165d..a3b2ab85d58 100644
--- a/src/rustc/middle/trans/closure.rs
+++ b/src/rustc/middle/trans/closure.rs
@@ -116,7 +116,7 @@ fn ev_to_str(ccx: @crate_ctxt, ev: environment_value) -> str {
 }
 
 fn mk_tuplified_uniq_cbox_ty(tcx: ty::ctxt, cdata_ty: ty::t) -> ty::t {
-    let cbox_ty = tuplify_cbox_ty(tcx, cdata_ty, ty::mk_type(tcx));
+    let cbox_ty = tuplify_box_ty(tcx, cdata_ty);
     ret ty::mk_imm_uniq(tcx, cbox_ty);
 }
 
@@ -179,10 +179,7 @@ fn allocate_cbox(bcx: block,
         (bcx, box)
       }
       ty::ck_uniq {
-        let uniq_cbox_ty = mk_tuplified_uniq_cbox_ty(tcx, cdata_ty);
-        let box = uniq::alloc_uniq(bcx, uniq_cbox_ty);
-        nuke_ref_count(bcx, box);
-        let bcx = store_tydesc(bcx, cdata_ty, box, ti);
+        let box = malloc_unique_raw(bcx, cdata_ty);
         (bcx, box)
       }
       ty::ck_block {
@@ -557,8 +554,8 @@ fn make_opaque_cbox_take_glue(
         let sz = Add(bcx, sz, shape::llsize_of(ccx, T_box_header(ccx)));
 
         // Allocate memory, update original ptr, and copy existing data
-        let malloc = ccx.upcalls.shared_malloc;
-        let cbox_out = Call(bcx, malloc, [sz]);
+        let malloc = ccx.upcalls.exchange_malloc;
+        let cbox_out = Call(bcx, malloc, [tydesc]);
         let cbox_out = PointerCast(bcx, cbox_out, llopaquecboxty);
         call_memmove(bcx, cbox_out, cbox_in, sz);
         Store(bcx, cbox_out, cboxptr);
@@ -606,7 +603,7 @@ fn make_opaque_cbox_free_glue(
       ty::ck_box | ty::ck_uniq { /* hard cases: */ }
     }
 
-    let ccx = bcx.ccx(), tcx = ccx.tcx;
+    let ccx = bcx.ccx();
     with_cond(bcx, IsNotNull(bcx, cbox)) {|bcx|
         // Load the type descr found in the cbox
         let lltydescty = T_ptr(ccx.tydesc_type);
@@ -628,8 +625,7 @@ fn make_opaque_cbox_free_glue(
             trans_free(bcx, cbox)
           }
           ty::ck_uniq {
-            let bcx = free_ty(bcx, tydesc, ty::mk_type(tcx));
-            trans_shared_free(bcx, cbox)
+            trans_unique_free(bcx, cbox)
           }
         }
     }
diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs
index c0994192a4e..194a1993ce3 100644
--- a/src/rustc/middle/trans/common.rs
+++ b/src/rustc/middle/trans/common.rs
@@ -271,7 +271,7 @@ fn add_clean_temp_mem(cx: block, val: ValueRef, ty: ty::t) {
     }
 }
 fn add_clean_free(cx: block, ptr: ValueRef, shared: bool) {
-    let free_fn = if shared { bind base::trans_shared_free(_, ptr) }
+    let free_fn = if shared { bind base::trans_unique_free(_, ptr) }
                   else { bind base::trans_free(_, ptr) };
     in_scope_cx(cx) {|info|
         info.cleanups += [clean_temp(ptr, free_fn,
@@ -654,15 +654,8 @@ fn T_opaque_vec(targ_cfg: @session::config) -> TypeRef {
 // representation of @T as a tuple (i.e., the ty::t version of what T_box()
 // returns).
 fn tuplify_box_ty(tcx: ty::ctxt, t: ty::t) -> ty::t {
-    ret tuplify_cbox_ty(tcx, t, ty::mk_type(tcx));
-}
-
-// As tuplify_box_ty(), but allows the caller to specify what type of type
-// descr is embedded in the box (ty::type vs ty::send_type).  This is useful
-// for unique closure boxes, hence the name "cbox_ty" (closure box type).
-fn tuplify_cbox_ty(tcx: ty::ctxt, t: ty::t, tydesc_t: ty::t) -> ty::t {
     let ptr = ty::mk_ptr(tcx, {ty: ty::mk_nil(tcx), mutbl: ast::m_imm});
-    ret ty::mk_tup(tcx, [ty::mk_uint(tcx), tydesc_t,
+    ret ty::mk_tup(tcx, [ty::mk_uint(tcx), ty::mk_type(tcx),
                          ptr, ptr,
                          t]);
 }
@@ -693,6 +686,15 @@ fn T_opaque_box_ptr(cx: @crate_ctxt) -> TypeRef {
     ret T_box_ptr(T_opaque_box(cx));
 }
 
+fn T_unique(cx: @crate_ctxt, t: TypeRef) -> TypeRef {
+    ret T_struct(T_box_header_fields(cx) + [t]);
+}
+
+fn T_unique_ptr(t: TypeRef) -> TypeRef {
+    const unique_addrspace: uint = 0u;
+    ret llvm::LLVMPointerType(t, unique_addrspace as c_uint);
+}
+
 fn T_port(cx: @crate_ctxt, _t: TypeRef) -> TypeRef {
     ret T_struct([cx.int_type]); // Refcount
 
diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs
index bcc5bbc3fa0..e37806dccf8 100644
--- a/src/rustc/middle/trans/tvec.rs
+++ b/src/rustc/middle/trans/tvec.rs
@@ -2,7 +2,7 @@ import syntax::ast;
 import driver::session::session;
 import lib::llvm::{ValueRef, TypeRef};
 import back::abi;
-import base::{call_memmove, shared_malloc,
+import base::{call_memmove,
                INIT, copy_val, load_if_immediate, get_tydesc,
                sub_block, do_spill_noroot,
                dest, bcx_icx};
@@ -21,6 +21,24 @@ fn set_fill(bcx: block, vptr: ValueRef, fill: ValueRef) {
 fn get_alloc(bcx: block, vptr: ValueRef) -> ValueRef {
     Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_alloc]))
 }
+
+fn get_bodyptr(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> ValueRef {
+    let ccx = bcx.ccx();
+    alt ty::get(vec_ty).struct {
+      ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq)
+      | ty::ty_vec(_) | ty::ty_str {
+        let boxptr = PointerCast(bcx, vptr, T_ptr(T_box_header(ccx)));
+        let bodyptr = GEPi(bcx, boxptr, [1u]);
+        let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
+        let llunit_ty = type_of::type_of(ccx, unit_ty);
+        PointerCast(bcx, bodyptr, T_ptr(T_vec(ccx, llunit_ty)))
+      }
+      _ {
+        vptr
+      }
+    }
+}
+
 fn get_dataptr(bcx: block, vptr: ValueRef, unit_ty: TypeRef)
     -> ValueRef {
     let _icx = bcx.insn_ctxt("tvec::get_dataptr");
@@ -35,41 +53,55 @@ fn pointer_add(bcx: block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
     ret PointerCast(bcx, InBoundsGEP(bcx, bptr, [bytes]), old_ty);
 }
 
-fn alloc_uniq_raw(bcx: block, fill: ValueRef, alloc: ValueRef) -> result {
+fn alloc_uniq_raw(bcx: block, unit_ty: ty::t,
+                  fill: ValueRef, alloc: ValueRef) -> result {
     let _icx = bcx.insn_ctxt("tvec::alloc_uniq_raw");
     let ccx = bcx.ccx();
-    let llvecty = ccx.opaque_vec_type;
+    let llunitty = type_of::type_of(ccx, unit_ty);
+    let llvecty = T_vec(ccx, llunitty);
     let vecsize = Add(bcx, alloc, llsize_of(ccx, llvecty));
-    let vecptr = shared_malloc(bcx, T_ptr(llvecty), vecsize);
-    Store(bcx, fill, GEPi(bcx, vecptr, [0u, abi::vec_elt_fill]));
-    Store(bcx, alloc, GEPi(bcx, vecptr, [0u, abi::vec_elt_alloc]));
-    ret {bcx: bcx, val: vecptr};
+    let vecbodyty = unit_ty; // FIXME: This is not the correct type
+    let {box, body} = base::malloc_unique_dyn(bcx, vecbodyty, vecsize);
+    let boxptr = PointerCast(bcx, box,
+                             T_unique_ptr(T_unique(bcx.ccx(), llvecty)));
+    let bodyptr = PointerCast(bcx, body, T_ptr(llvecty));
+    Store(bcx, fill, GEPi(bcx, bodyptr, [0u, abi::vec_elt_fill]));
+    Store(bcx, alloc, GEPi(bcx, bodyptr, [0u, abi::vec_elt_alloc]));
+    ret {bcx: bcx, val: boxptr};
 }
 
-fn alloc_uniq(bcx: block, llunitty: TypeRef, elts: uint) -> result {
+fn alloc_uniq(bcx: block, unit_ty: ty::t, elts: uint) -> result {
     let _icx = bcx.insn_ctxt("tvec::alloc_uniq");
     let ccx = bcx.ccx();
-    let llvecty = T_vec(ccx, llunitty);
+    let llunitty = type_of::type_of(ccx, unit_ty);
     let unit_sz = llsize_of(ccx, llunitty);
 
     let fill = Mul(bcx, C_uint(ccx, elts), unit_sz);
     let alloc = if elts < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) }
                 else { fill };
-    let {bcx: bcx, val: vptr} = alloc_uniq_raw(bcx, fill, alloc);
-    let vptr = PointerCast(bcx, vptr, T_ptr(llvecty));
-
+    let {bcx: bcx, val: vptr} = alloc_uniq_raw(bcx, unit_ty, fill, alloc);
     ret {bcx: bcx, val: vptr};
 }
 
 fn duplicate_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> result {
     let _icx = bcx.insn_ctxt("tvec::duplicate_uniq");
     let ccx = bcx.ccx();
-    let fill = get_fill(bcx, vptr);
+    let body_ptr = get_bodyptr(bcx, vptr, vec_ty);
+    let fill = get_fill(bcx, body_ptr);
     let size = Add(bcx, fill, llsize_of(ccx, ccx.opaque_vec_type));
-    let newptr = shared_malloc(bcx, val_ty(vptr), size);
-    call_memmove(bcx, newptr, vptr, size);
+
     let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
-    Store(bcx, fill, GEPi(bcx, newptr, [0u, abi::vec_elt_alloc]));
+    let llunitty = type_of::type_of(ccx, unit_ty);
+    let llvecty = T_vec(ccx, llunitty);
+    let vecbodyty = unit_ty; // FIXME: This is not the correct type
+    let {box: newptr, body: new_body_ptr} =
+        base::malloc_unique_dyn(bcx, vecbodyty, size);
+    let newptr = PointerCast(bcx, newptr,
+                             T_unique_ptr(T_unique(bcx.ccx(), llvecty)));
+    let new_body_ptr = PointerCast(bcx, new_body_ptr, T_ptr(llvecty));
+    call_memmove(bcx, new_body_ptr, body_ptr, size);
+
+    Store(bcx, fill, GEPi(bcx, new_body_ptr, [0u, abi::vec_elt_alloc]));
     let bcx = if ty::type_needs_drop(bcx.tcx(), unit_ty) {
         iter_vec(bcx, newptr, vec_ty, base::take_ty)
     } else { bcx };
@@ -83,7 +115,7 @@ fn make_free_glue(bcx: block, vptr: ValueRef, vec_ty: ty::t) ->
         let bcx = if ty::type_needs_drop(tcx, unit_ty) {
             iter_vec(bcx, vptr, vec_ty, base::drop_ty)
         } else { bcx };
-        base::trans_shared_free(bcx, vptr)
+        base::trans_unique_free(bcx, vptr)
     }
 }
 
@@ -133,9 +165,10 @@ fn trans_evec(bcx: block, args: [@ast::expr],
             {bcx: bcx, val: p, dataptr: vp}
           }
           ast::vstore_uniq {
-            let {bcx, val} = alloc_uniq(bcx, llunitty, args.len());
+            let {bcx, val} = alloc_uniq(bcx, unit_ty, args.len());
             add_clean_free(bcx, val, true);
-            let dataptr = get_dataptr(bcx, val, llunitty);
+            let body = get_bodyptr(bcx, val, vec_ty);
+            let dataptr = get_dataptr(bcx, body, llunitty);
             {bcx: bcx, val: val, dataptr: dataptr}
           }
           ast::vstore_box {
@@ -216,8 +249,9 @@ fn get_base_and_len(cx: block, v: ValueRef, e_ty: ty::t)
         (base, len)
       }
       ty::vstore_uniq {
-        let base = tvec::get_dataptr(cx, v, llunitty);
-        let len = tvec::get_fill(cx, v);
+        let body = tvec::get_bodyptr(cx, v, vec_ty);
+        let base = tvec::get_dataptr(cx, body, llunitty);
+        let len = tvec::get_fill(cx, body);
         (base, len)
       }
       ty::vstore_box {
@@ -249,7 +283,9 @@ fn trans_estr(bcx: block, s: str, vstore: ast::vstore,
       ast::vstore_uniq {
         let cs = PointerCast(bcx, C_cstr(ccx, s), T_ptr(T_i8()));
         let len = C_uint(ccx, str::len(s));
-        Call(bcx, ccx.upcalls.str_new_uniq, [cs, len])
+        let c = Call(bcx, ccx.upcalls.str_new_uniq, [cs, len]);
+        PointerCast(bcx, c,
+                    T_unique_ptr(T_unique(ccx, T_vec(ccx, T_i8()))))
       }
 
       ast::vstore_box {
@@ -274,19 +310,23 @@ fn trans_append(bcx: block, vec_ty: ty::t, lhsptr: ValueRef,
 
     let lhs = Load(bcx, lhsptr);
     let self_append = ICmp(bcx, lib::llvm::IntEQ, lhs, rhs);
-    let lfill = get_fill(bcx, lhs);
-    let rfill = get_fill(bcx, rhs);
+    let lbody = get_bodyptr(bcx, lhs, vec_ty);
+    let rbody = get_bodyptr(bcx, rhs, vec_ty);
+    let lfill = get_fill(bcx, lbody);
+    let rfill = get_fill(bcx, rbody);
     let mut new_fill = Add(bcx, lfill, rfill);
     if strings { new_fill = Sub(bcx, new_fill, C_int(ccx, 1)); }
     let opaque_lhs = PointerCast(bcx, lhsptr,
-                                 T_ptr(T_ptr(ccx.opaque_vec_type)));
+                                 T_ptr(T_ptr(T_i8())));
     Call(bcx, ccx.upcalls.vec_grow,
          [opaque_lhs, new_fill]);
     // Was overwritten if we resized
     let lhs = Load(bcx, lhsptr);
     let rhs = Select(bcx, self_append, lhs, rhs);
 
-    let lhs_data = get_dataptr(bcx, lhs, llunitty);
+    let lbody = get_bodyptr(bcx, lhs, vec_ty);
+
+    let lhs_data = get_dataptr(bcx, lbody, llunitty);
     let mut lhs_off = lfill;
     if strings { lhs_off = Sub(bcx, lhs_off, C_int(ccx, 1)); }
     let write_ptr = pointer_add(bcx, lhs_data, lhs_off);
@@ -311,18 +351,18 @@ fn trans_append_literal(bcx: block, vptrptr: ValueRef, vec_ty: ty::t,
     let scratch = base::alloca(bcx, elt_llty);
     for vec::each(vals) {|val|
         bcx = base::trans_expr_save_in(bcx, val, scratch);
-        let vptr = Load(bcx, vptrptr);
+        let vptr = get_bodyptr(bcx, Load(bcx, vptrptr), vec_ty);
         let old_fill = get_fill(bcx, vptr);
         let new_fill = Add(bcx, old_fill, elt_sz);
         let do_grow = ICmp(bcx, lib::llvm::IntUGT, new_fill,
                            get_alloc(bcx, vptr));
         bcx = base::with_cond(bcx, do_grow) {|bcx|
             let pt = PointerCast(bcx, vptrptr,
-                                 T_ptr(T_ptr(ccx.opaque_vec_type)));
+                                 T_ptr(T_ptr(T_i8())));
             Call(bcx, ccx.upcalls.vec_grow, [pt, new_fill]);
             bcx
         };
-        let vptr = Load(bcx, vptrptr);
+        let vptr = get_bodyptr(bcx, Load(bcx, vptrptr), vec_ty);
         set_fill(bcx, vptr, new_fill);
         let targetptr = pointer_add(bcx, get_dataptr(bcx, vptr, elt_llty),
                                     old_fill);
@@ -336,23 +376,30 @@ fn trans_add(bcx: block, vec_ty: ty::t, lhs: ValueRef,
     let _icx = bcx.insn_ctxt("tvec::trans_add");
     let ccx = bcx.ccx();
 
+    let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
+    let llunitty = type_of::type_of(ccx, unit_ty);
+
     if ty::get(vec_ty).struct == ty::ty_str {
+        let lhs = PointerCast(bcx, lhs, T_ptr(T_i8()));
+        let rhs = PointerCast(bcx, rhs, T_ptr(T_i8()));
         let n = Call(bcx, ccx.upcalls.str_concat, [lhs, rhs]);
+        let n = PointerCast(
+            bcx, n, T_unique_ptr(T_unique(ccx, T_vec(ccx, llunitty))));
         ret base::store_in_dest(bcx, n, dest);
     }
 
-    let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
-    let llunitty = type_of::type_of(ccx, unit_ty);
+    let lhs_body = get_bodyptr(bcx, lhs, vec_ty);
+    let rhs_body = get_bodyptr(bcx, rhs, vec_ty);
 
-    let lhs_fill = get_fill(bcx, lhs);
-    let rhs_fill = get_fill(bcx, rhs);
+    let lhs_fill = get_fill(bcx, lhs_body);
+    let rhs_fill = get_fill(bcx, rhs_body);
     let new_fill = Add(bcx, lhs_fill, rhs_fill);
     let mut {bcx: bcx, val: new_vec_ptr} =
-        alloc_uniq_raw(bcx, new_fill, new_fill);
-    new_vec_ptr = PointerCast(bcx, new_vec_ptr, T_ptr(T_vec(ccx, llunitty)));
+        alloc_uniq_raw(bcx, unit_ty, new_fill, new_fill);
 
+    let new_vec_body_ptr = get_bodyptr(bcx, new_vec_ptr, vec_ty);
     let write_ptr_ptr = do_spill_noroot
-        (bcx, get_dataptr(bcx, new_vec_ptr, llunitty));
+        (bcx, get_dataptr(bcx, new_vec_body_ptr, llunitty));
     let copy_fn = fn@(bcx: block, addr: ValueRef,
                       _ty: ty::t) -> block {
         let ccx = bcx.ccx();
@@ -408,16 +455,17 @@ fn iter_vec_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t,
     let ccx = bcx.ccx();
     let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
     let llunitty = type_of::type_of(ccx, unit_ty);
-    let vptr = PointerCast(bcx, vptr, T_ptr(T_vec(ccx, llunitty)));
-    let data_ptr = get_dataptr(bcx, vptr, llunitty);
+    let body_ptr = get_bodyptr(bcx, vptr, vec_ty);
+    let data_ptr = get_dataptr(bcx, body_ptr, llunitty);
     iter_vec_raw(bcx, data_ptr, vec_ty, fill, f)
 }
 
 fn iter_vec(bcx: block, vptr: ValueRef, vec_ty: ty::t,
             f: iter_vec_block) -> block {
     let _icx = bcx.insn_ctxt("tvec::iter_vec");
-    let vptr = PointerCast(bcx, vptr, T_ptr(bcx.ccx().opaque_vec_type));
-    ret iter_vec_uniq(bcx, vptr, vec_ty, get_fill(bcx, vptr), f);
+    let body_ptr = get_bodyptr(bcx, vptr, vec_ty);
+    let fill = get_fill(bcx, body_ptr);
+    ret iter_vec_uniq(bcx, vptr, vec_ty, fill, f);
 }
 
 //
diff --git a/src/rustc/middle/trans/type_of.rs b/src/rustc/middle/trans/type_of.rs
index b094a576cb1..fedd7c713cf 100644
--- a/src/rustc/middle/trans/type_of.rs
+++ b/src/rustc/middle/trans/type_of.rs
@@ -85,15 +85,19 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
           ty::ty_uint(t) { T_uint_ty(cx, t) }
           ty::ty_float(t) { T_float_ty(cx, t) }
           ty::ty_estr(ty::vstore_uniq) |
-          ty::ty_str { T_ptr(T_vec(cx, T_i8())) }
+          ty::ty_str {
+            T_unique_ptr(T_unique(cx, T_vec(cx, T_i8())))
+          }
           ty::ty_enum(did, _) { type_of_enum(cx, did, t) }
           ty::ty_estr(ty::vstore_box) { T_box_ptr(T_box(cx, T_i8())) }
           ty::ty_evec(mt, ty::vstore_box) |
           ty::ty_box(mt) { T_box_ptr(T_box(cx, type_of(cx, mt.ty))) }
           ty::ty_opaque_box { T_box_ptr(T_box(cx, T_i8())) }
-          ty::ty_uniq(mt) { T_ptr(type_of(cx, mt.ty)) }
+          ty::ty_uniq(mt) { T_unique_ptr(T_unique(cx, type_of(cx, mt.ty))) }
           ty::ty_evec(mt, ty::vstore_uniq) |
-          ty::ty_vec(mt) { T_ptr(T_vec(cx, type_of(cx, mt.ty))) }
+          ty::ty_vec(mt) {
+            T_unique_ptr(T_unique(cx, T_vec(cx, type_of(cx, mt.ty))))
+          }
           ty::ty_ptr(mt) { T_ptr(type_of(cx, mt.ty)) }
           ty::ty_rptr(_, mt) { T_ptr(type_of(cx, mt.ty)) }
 
diff --git a/src/rustc/middle/trans/uniq.rs b/src/rustc/middle/trans/uniq.rs
index bac8033e6ea..a3325fc4904 100644
--- a/src/rustc/middle/trans/uniq.rs
+++ b/src/rustc/middle/trans/uniq.rs
@@ -5,34 +5,28 @@ import build::*;
 import base::*;
 import shape::llsize_of;
 
-export trans_uniq, make_free_glue, autoderef, duplicate, alloc_uniq;
+export trans_uniq, make_free_glue, autoderef, duplicate;
 
 fn trans_uniq(bcx: block, contents: @ast::expr,
               node_id: ast::node_id, dest: dest) -> block {
     let _icx = bcx.insn_ctxt("uniq::trans_uniq");
     let uniq_ty = node_id_type(bcx, node_id);
-    let llptr = alloc_uniq(bcx, uniq_ty);
-    add_clean_free(bcx, llptr, true);
-    let bcx = trans_expr_save_in(bcx, contents, llptr);
-    revoke_clean(bcx, llptr);
-    ret store_in_dest(bcx, llptr, dest);
-}
-
-fn alloc_uniq(bcx: block, uniq_ty: ty::t) -> ValueRef {
-    let _icx = bcx.insn_ctxt("uniq::alloc_uniq");
     let contents_ty = content_ty(uniq_ty);
-    let llty = type_of::type_of(bcx.ccx(), contents_ty);
-    let llsz = llsize_of(bcx.ccx(), llty);
-    let llptrty = T_ptr(llty);
-    shared_malloc(bcx, llptrty, llsz)
+    let {box, body} = malloc_unique(bcx, contents_ty);
+    add_clean_free(bcx, box, true);
+    let bcx = trans_expr_save_in(bcx, contents, body);
+    revoke_clean(bcx, box);
+    ret store_in_dest(bcx, box, dest);
 }
 
 fn make_free_glue(bcx: block, vptr: ValueRef, t: ty::t)
     -> block {
     let _icx = bcx.insn_ctxt("uniq::make_free_glue");
     with_cond(bcx, IsNotNull(bcx, vptr)) {|bcx|
-        let bcx = drop_ty(bcx, vptr, content_ty(t));
-        trans_shared_free(bcx, vptr)
+        let content_ty = content_ty(t);
+        let body_ptr = opaque_box_body(bcx, content_ty, vptr);
+        let bcx = drop_ty(bcx, body_ptr, content_ty);
+        trans_unique_free(bcx, vptr)
     }
 }
 
@@ -43,18 +37,31 @@ fn content_ty(t: ty::t) -> ty::t {
     }
 }
 
-fn autoderef(v: ValueRef, t: ty::t) -> {v: ValueRef, t: ty::t} {
+fn autoderef(bcx: block, v: ValueRef, t: ty::t) -> {v: ValueRef, t: ty::t} {
     let content_ty = content_ty(t);
+    let v = opaque_box_body(bcx, content_ty, v);
     ret {v: v, t: content_ty};
 }
 
 fn duplicate(bcx: block, v: ValueRef, t: ty::t) -> result {
     let _icx = bcx.insn_ctxt("uniq::duplicate");
     let content_ty = content_ty(t);
-    let llptr = alloc_uniq(bcx, t);
+    let {box: dst_box, body: dst_body} = malloc_unique(bcx, content_ty);
+
+    let src_box = v;
+    let src_body = opaque_box_body(bcx, content_ty, src_box);
+    let src_body = load_if_immediate(bcx, src_body, content_ty);
+    #debug("ST: %?", val_str(bcx.ccx().tn, src_body));
+    #debug("DT: %?", val_str(bcx.ccx().tn, dst_body));
+    let bcx = copy_val(bcx, INIT, dst_body, src_body, content_ty);
+
+    let src_tydesc_ptr = GEPi(bcx, src_box,
+                              [0u, back::abi::box_field_tydesc]);
+    let dst_tydesc_ptr = GEPi(bcx, dst_box,
+                              [0u, back::abi::box_field_tydesc]);
+
+    let td = Load(bcx, src_tydesc_ptr);
+    Store(bcx, td, dst_tydesc_ptr);
 
-    let src = load_if_immediate(bcx, v, content_ty);
-    let dst = llptr;
-    let bcx = copy_val(bcx, INIT, dst, src, content_ty);
-    ret rslt(bcx, dst);
+    ret rslt(bcx, dst_box);
 }
\ No newline at end of file
diff --git a/src/snapshots.txt b/src/snapshots.txt
index 5ca29713c44..c8546daf238 100644
--- a/src/snapshots.txt
+++ b/src/snapshots.txt
@@ -1,3 +1,11 @@
+S 2012-05-30 0c0818b
+  winnt-i386 910bc6b562e8e310e99f8174292f2b0a0d93ef6c
+  linux-x86_64 482bfe7c000bc798945524dd750d3e06be2c0283
+  linux-i386 f794e99472bc59773fa5281a4f9e2875e59f812f
+  freebsd-x86_64 29ec0b56d05c59e3a6eec2a97f17e2429c1a6331
+  macos-x86_64 d562f05c8911e7405b0a9ff5815f49fca69045d3
+  macos-i386 4d09cc2a4882d92f125718161e3d7086531748e6
+
 S 2012-05-30 02dde78
   winnt-i386 b394e3db0639942a9844ce6f78d34239a90127af
   linux-x86_64 bd3128bce34f2f131f37bc1c7077a4d2e367ff50