about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-02-07 19:31:31 -0800
committerbors <bors@rust-lang.org>2014-02-07 19:31:31 -0800
commit80c6c73647cc3294c587d8089d6628d8969f0b71 (patch)
tree7a6e789f7123151a8fd0e4b2fe1bd7abfb7e0dcf
parent29e500db8a98a86b3de56688cd9fa6571a840470 (diff)
parent95d897c579621d92a17e9f0bc4edb3ffa24477c7 (diff)
auto merge of #12059 : thestinger/rust/glue, r=pcwalton
A follow-up from the work I started with 383e3fd13b99827b5dbb107da7433bd0a70dea80.
-rw-r--r--src/libarena/lib.rs5
-rw-r--r--src/librustc/middle/trans/base.rs10
-rw-r--r--src/librustc/middle/trans/common.rs1
-rw-r--r--src/librustc/middle/trans/context.rs260
-rw-r--r--src/librustc/middle/trans/debuginfo.rs4
-rw-r--r--src/librustc/middle/trans/glue.rs214
-rw-r--r--src/librustc/middle/trans/intrinsic.rs6
-rw-r--r--src/librustc/middle/trans/meth.rs12
-rw-r--r--src/librustc/middle/trans/reflect.rs2
-rw-r--r--src/librustc/middle/trans/type_.rs2
-rw-r--r--src/libstd/cleanup.rs71
-rw-r--r--src/libstd/rt/env.rs2
-rw-r--r--src/libstd/rt/global_heap.rs27
-rw-r--r--src/libstd/rt/local_heap.rs61
-rw-r--r--src/libstd/unstable/lang.rs8
-rw-r--r--src/libstd/unstable/raw.rs15
-rw-r--r--src/test/debug-info/basic-types-metadata.rs2
17 files changed, 387 insertions, 315 deletions
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index cd9b638a5c2..856540989df 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -214,8 +214,7 @@ impl Arena {
     #[inline]
     fn alloc_pod<'a, T>(&'a mut self, op: || -> T) -> &'a T {
         unsafe {
-            let tydesc = get_tydesc::<T>();
-            let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align);
+            let ptr = self.alloc_pod_inner(mem::size_of::<T>(), mem::min_align_of::<T>());
             let ptr: *mut T = transmute(ptr);
             intrinsics::move_val_init(&mut (*ptr), op());
             return transmute(ptr);
@@ -272,7 +271,7 @@ impl Arena {
         unsafe {
             let tydesc = get_tydesc::<T>();
             let (ty_ptr, ptr) =
-                self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align);
+                self.alloc_nonpod_inner(mem::size_of::<T>(), mem::min_align_of::<T>());
             let ty_ptr: *mut uint = transmute(ty_ptr);
             let ptr: *mut T = transmute(ptr);
             // Write in our tydesc along with a bit indicating that it
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 485daf3d387..39e0ca176eb 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -352,7 +352,6 @@ pub fn malloc_raw_dyn<'a>(
     if heap == heap_exchange {
         let llty_value = type_of::type_of(ccx, t);
 
-
         // Allocate space:
         let r = callee::trans_lang_call(
             bcx,
@@ -375,17 +374,14 @@ pub fn malloc_raw_dyn<'a>(
         // Grab the TypeRef type of box_ptr_ty.
         let box_ptr_ty = ty::mk_box(bcx.tcx(), t);
         let llty = type_of(ccx, box_ptr_ty);
-
-        // Get the tydesc for the body:
-        let static_ti = get_tydesc(ccx, t);
-        glue::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti);
+        let llalign = C_uint(ccx, llalign_of_min(ccx, llty) as uint);
 
         // Allocate space:
-        let tydesc = PointerCast(bcx, static_ti.tydesc, Type::i8p());
+        let drop_glue = glue::get_drop_glue(ccx, t);
         let r = callee::trans_lang_call(
             bcx,
             langcall,
-            [tydesc, size],
+            [PointerCast(bcx, drop_glue, Type::glue_fn(Type::i8p()).ptr_to()), size, llalign],
             None);
         rslt(r.bcx, PointerCast(r.bcx, r.val, llty))
     }
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 78affcc69e1..7ee77e4c0d6 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -114,7 +114,6 @@ pub struct tydesc_info {
     size: ValueRef,
     align: ValueRef,
     name: ValueRef,
-    drop_glue: Cell<Option<ValueRef>>,
     visit_glue: Cell<Option<ValueRef>>,
 }
 
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index 93d874cf83e..95875a01401 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -36,83 +36,84 @@ use syntax::ast;
 use syntax::parse::token::InternedString;
 
 pub struct CrateContext {
-     sess: session::Session,
-     llmod: ModuleRef,
-     llcx: ContextRef,
-     metadata_llmod: ModuleRef,
-     td: TargetData,
-     tn: TypeNames,
-     externs: RefCell<ExternMap>,
-     intrinsics: HashMap<&'static str, ValueRef>,
-     item_vals: RefCell<HashMap<ast::NodeId, ValueRef>>,
-     exp_map2: resolve::ExportMap2,
-     reachable: @RefCell<HashSet<ast::NodeId>>,
-     item_symbols: RefCell<HashMap<ast::NodeId, ~str>>,
-     link_meta: LinkMeta,
-     tydescs: RefCell<HashMap<ty::t, @tydesc_info>>,
-     // Set when running emit_tydescs to enforce that no more tydescs are
-     // created.
-     finished_tydescs: Cell<bool>,
-     // Track mapping of external ids to local items imported for inlining
-     external: RefCell<HashMap<ast::DefId, Option<ast::NodeId>>>,
-     // Backwards version of the `external` map (inlined items to where they
-     // came from)
-     external_srcs: RefCell<HashMap<ast::NodeId, ast::DefId>>,
-     // A set of static items which cannot be inlined into other crates. This
-     // will pevent in IIItem() structures from being encoded into the metadata
-     // that is generated
-     non_inlineable_statics: RefCell<HashSet<ast::NodeId>>,
-     // Cache instances of monomorphized functions
-     monomorphized: RefCell<HashMap<mono_id, ValueRef>>,
-     monomorphizing: RefCell<HashMap<ast::DefId, uint>>,
-     // Cache generated vtables
-     vtables: RefCell<HashMap<(ty::t, mono_id), ValueRef>>,
-     // Cache of constant strings,
-     const_cstr_cache: RefCell<HashMap<InternedString, ValueRef>>,
+    sess: session::Session,
+    llmod: ModuleRef,
+    llcx: ContextRef,
+    metadata_llmod: ModuleRef,
+    td: TargetData,
+    tn: TypeNames,
+    externs: RefCell<ExternMap>,
+    intrinsics: HashMap<&'static str, ValueRef>,
+    item_vals: RefCell<HashMap<ast::NodeId, ValueRef>>,
+    exp_map2: resolve::ExportMap2,
+    reachable: @RefCell<HashSet<ast::NodeId>>,
+    item_symbols: RefCell<HashMap<ast::NodeId, ~str>>,
+    link_meta: LinkMeta,
+    drop_glues: RefCell<HashMap<ty::t, ValueRef>>,
+    tydescs: RefCell<HashMap<ty::t, @tydesc_info>>,
+    // Set when running emit_tydescs to enforce that no more tydescs are
+    // created.
+    finished_tydescs: Cell<bool>,
+    // Track mapping of external ids to local items imported for inlining
+    external: RefCell<HashMap<ast::DefId, Option<ast::NodeId>>>,
+    // Backwards version of the `external` map (inlined items to where they
+    // came from)
+    external_srcs: RefCell<HashMap<ast::NodeId, ast::DefId>>,
+    // A set of static items which cannot be inlined into other crates. This
+    // will pevent in IIItem() structures from being encoded into the metadata
+    // that is generated
+    non_inlineable_statics: RefCell<HashSet<ast::NodeId>>,
+    // Cache instances of monomorphized functions
+    monomorphized: RefCell<HashMap<mono_id, ValueRef>>,
+    monomorphizing: RefCell<HashMap<ast::DefId, uint>>,
+    // Cache generated vtables
+    vtables: RefCell<HashMap<(ty::t, mono_id), ValueRef>>,
+    // Cache of constant strings,
+    const_cstr_cache: RefCell<HashMap<InternedString, ValueRef>>,
 
-     // Reverse-direction for const ptrs cast from globals.
-     // Key is an int, cast from a ValueRef holding a *T,
-     // Val is a ValueRef holding a *[T].
-     //
-     // Needed because LLVM loses pointer->pointee association
-     // when we ptrcast, and we have to ptrcast during translation
-     // of a [T] const because we form a slice, a [*T,int] pair, not
-     // a pointer to an LLVM array type.
-     const_globals: RefCell<HashMap<int, ValueRef>>,
+    // Reverse-direction for const ptrs cast from globals.
+    // Key is an int, cast from a ValueRef holding a *T,
+    // Val is a ValueRef holding a *[T].
+    //
+    // Needed because LLVM loses pointer->pointee association
+    // when we ptrcast, and we have to ptrcast during translation
+    // of a [T] const because we form a slice, a [*T,int] pair, not
+    // a pointer to an LLVM array type.
+    const_globals: RefCell<HashMap<int, ValueRef>>,
 
-     // Cache of emitted const values
-     const_values: RefCell<HashMap<ast::NodeId, ValueRef>>,
+    // Cache of emitted const values
+    const_values: RefCell<HashMap<ast::NodeId, ValueRef>>,
 
-     // Cache of external const values
-     extern_const_values: RefCell<HashMap<ast::DefId, ValueRef>>,
+    // Cache of external const values
+    extern_const_values: RefCell<HashMap<ast::DefId, ValueRef>>,
 
-     impl_method_cache: RefCell<HashMap<(ast::DefId, ast::Name), ast::DefId>>,
+    impl_method_cache: RefCell<HashMap<(ast::DefId, ast::Name), ast::DefId>>,
 
-     // Cache of closure wrappers for bare fn's.
-     closure_bare_wrapper_cache: RefCell<HashMap<ValueRef, ValueRef>>,
+    // Cache of closure wrappers for bare fn's.
+    closure_bare_wrapper_cache: RefCell<HashMap<ValueRef, ValueRef>>,
 
-     module_data: RefCell<HashMap<~str, ValueRef>>,
-     lltypes: RefCell<HashMap<ty::t, Type>>,
-     llsizingtypes: RefCell<HashMap<ty::t, Type>>,
-     adt_reprs: RefCell<HashMap<ty::t, @adt::Repr>>,
-     symbol_hasher: RefCell<Sha256>,
-     type_hashcodes: RefCell<HashMap<ty::t, ~str>>,
-     all_llvm_symbols: RefCell<HashSet<~str>>,
-     tcx: ty::ctxt,
-     maps: astencode::Maps,
-     stats: @Stats,
-     tydesc_type: Type,
-     int_type: Type,
-     opaque_vec_type: Type,
-     builder: BuilderRef_res,
-     crate_map: ValueRef,
-     crate_map_name: ~str,
-     // Set when at least one function uses GC. Needed so that
-     // decl_gc_metadata knows whether to link to the module metadata, which
-     // is not emitted by LLVM's GC pass when no functions use GC.
-     uses_gc: bool,
-     dbg_cx: Option<debuginfo::CrateDebugContext>,
-     do_not_commit_warning_issued: Cell<bool>,
+    module_data: RefCell<HashMap<~str, ValueRef>>,
+    lltypes: RefCell<HashMap<ty::t, Type>>,
+    llsizingtypes: RefCell<HashMap<ty::t, Type>>,
+    adt_reprs: RefCell<HashMap<ty::t, @adt::Repr>>,
+    symbol_hasher: RefCell<Sha256>,
+    type_hashcodes: RefCell<HashMap<ty::t, ~str>>,
+    all_llvm_symbols: RefCell<HashSet<~str>>,
+    tcx: ty::ctxt,
+    maps: astencode::Maps,
+    stats: @Stats,
+    tydesc_type: Type,
+    int_type: Type,
+    opaque_vec_type: Type,
+    builder: BuilderRef_res,
+    crate_map: ValueRef,
+    crate_map_name: ~str,
+    // Set when at least one function uses GC. Needed so that
+    // decl_gc_metadata knows whether to link to the module metadata, which
+    // is not emitted by LLVM's GC pass when no functions use GC.
+    uses_gc: bool,
+    dbg_cx: Option<debuginfo::CrateDebugContext>,
+    do_not_commit_warning_issued: Cell<bool>,
 }
 
 impl CrateContext {
@@ -175,64 +176,65 @@ impl CrateContext {
             }
 
             CrateContext {
-                  sess: sess,
-                  llmod: llmod,
-                  llcx: llcx,
-                  metadata_llmod: metadata_llmod,
-                  td: td,
-                  tn: tn,
-                  externs: RefCell::new(HashMap::new()),
-                  intrinsics: intrinsics,
-                  item_vals: RefCell::new(HashMap::new()),
-                  exp_map2: emap2,
-                  reachable: reachable,
-                  item_symbols: RefCell::new(HashMap::new()),
-                  link_meta: link_meta,
-                  tydescs: RefCell::new(HashMap::new()),
-                  finished_tydescs: Cell::new(false),
-                  external: RefCell::new(HashMap::new()),
-                  external_srcs: RefCell::new(HashMap::new()),
-                  non_inlineable_statics: RefCell::new(HashSet::new()),
-                  monomorphized: RefCell::new(HashMap::new()),
-                  monomorphizing: RefCell::new(HashMap::new()),
-                  vtables: RefCell::new(HashMap::new()),
-                  const_cstr_cache: RefCell::new(HashMap::new()),
-                  const_globals: RefCell::new(HashMap::new()),
-                  const_values: RefCell::new(HashMap::new()),
-                  extern_const_values: RefCell::new(HashMap::new()),
-                  impl_method_cache: RefCell::new(HashMap::new()),
-                  closure_bare_wrapper_cache: RefCell::new(HashMap::new()),
-                  module_data: RefCell::new(HashMap::new()),
-                  lltypes: RefCell::new(HashMap::new()),
-                  llsizingtypes: RefCell::new(HashMap::new()),
-                  adt_reprs: RefCell::new(HashMap::new()),
-                  symbol_hasher: RefCell::new(symbol_hasher),
-                  type_hashcodes: RefCell::new(HashMap::new()),
-                  all_llvm_symbols: RefCell::new(HashSet::new()),
-                  tcx: tcx,
-                  maps: maps,
-                  stats: @Stats {
-                    n_static_tydescs: Cell::new(0u),
-                    n_glues_created: Cell::new(0u),
-                    n_null_glues: Cell::new(0u),
-                    n_real_glues: Cell::new(0u),
-                    n_fns: Cell::new(0u),
-                    n_monos: Cell::new(0u),
-                    n_inlines: Cell::new(0u),
-                    n_closures: Cell::new(0u),
-                    n_llvm_insns: Cell::new(0u),
-                    llvm_insns: RefCell::new(HashMap::new()),
-                    fn_stats: RefCell::new(~[]),
-                  },
-                  tydesc_type: tydesc_type,
-                  int_type: int_type,
-                  opaque_vec_type: opaque_vec_type,
-                  builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
-                  crate_map: crate_map,
-                  crate_map_name: crate_map_name,
-                  uses_gc: false,
-                  dbg_cx: dbg_cx,
-                  do_not_commit_warning_issued: Cell::new(false),
+                 sess: sess,
+                 llmod: llmod,
+                 llcx: llcx,
+                 metadata_llmod: metadata_llmod,
+                 td: td,
+                 tn: tn,
+                 externs: RefCell::new(HashMap::new()),
+                 intrinsics: intrinsics,
+                 item_vals: RefCell::new(HashMap::new()),
+                 exp_map2: emap2,
+                 reachable: reachable,
+                 item_symbols: RefCell::new(HashMap::new()),
+                 link_meta: link_meta,
+                 drop_glues: RefCell::new(HashMap::new()),
+                 tydescs: RefCell::new(HashMap::new()),
+                 finished_tydescs: Cell::new(false),
+                 external: RefCell::new(HashMap::new()),
+                 external_srcs: RefCell::new(HashMap::new()),
+                 non_inlineable_statics: RefCell::new(HashSet::new()),
+                 monomorphized: RefCell::new(HashMap::new()),
+                 monomorphizing: RefCell::new(HashMap::new()),
+                 vtables: RefCell::new(HashMap::new()),
+                 const_cstr_cache: RefCell::new(HashMap::new()),
+                 const_globals: RefCell::new(HashMap::new()),
+                 const_values: RefCell::new(HashMap::new()),
+                 extern_const_values: RefCell::new(HashMap::new()),
+                 impl_method_cache: RefCell::new(HashMap::new()),
+                 closure_bare_wrapper_cache: RefCell::new(HashMap::new()),
+                 module_data: RefCell::new(HashMap::new()),
+                 lltypes: RefCell::new(HashMap::new()),
+                 llsizingtypes: RefCell::new(HashMap::new()),
+                 adt_reprs: RefCell::new(HashMap::new()),
+                 symbol_hasher: RefCell::new(symbol_hasher),
+                 type_hashcodes: RefCell::new(HashMap::new()),
+                 all_llvm_symbols: RefCell::new(HashSet::new()),
+                 tcx: tcx,
+                 maps: maps,
+                 stats: @Stats {
+                   n_static_tydescs: Cell::new(0u),
+                   n_glues_created: Cell::new(0u),
+                   n_null_glues: Cell::new(0u),
+                   n_real_glues: Cell::new(0u),
+                   n_fns: Cell::new(0u),
+                   n_monos: Cell::new(0u),
+                   n_inlines: Cell::new(0u),
+                   n_closures: Cell::new(0u),
+                   n_llvm_insns: Cell::new(0u),
+                   llvm_insns: RefCell::new(HashMap::new()),
+                   fn_stats: RefCell::new(~[]),
+                 },
+                 tydesc_type: tydesc_type,
+                 int_type: int_type,
+                 opaque_vec_type: opaque_vec_type,
+                 builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
+                 crate_map: crate_map,
+                 crate_map_name: crate_map_name,
+                 uses_gc: false,
+                 dbg_cx: dbg_cx,
+                 do_not_commit_warning_issued: Cell::new(false),
             }
         }
     }
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index ed233142238..7bbbf4f9905 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -1779,7 +1779,7 @@ fn boxed_type_metadata(cx: &CrateContext,
             offset: ComputedMemberOffset,
         },
         MemberDescription {
-            name: ~"tydesc",
+            name: ~"drop_glue",
             llvm_type: member_llvm_types[1],
             type_metadata: nil_pointer_type_metadata,
             offset: ComputedMemberOffset,
@@ -1824,7 +1824,7 @@ fn boxed_type_metadata(cx: &CrateContext,
                           -> bool {
         member_llvm_types.len() == 5 &&
         member_llvm_types[0] == cx.int_type &&
-        member_llvm_types[1] == cx.tydesc_type.ptr_to() &&
+        member_llvm_types[1] == Type::generic_glue_fn(cx).ptr_to() &&
         member_llvm_types[2] == Type::i8().ptr_to() &&
         member_llvm_types[3] == Type::i8().ptr_to() &&
         member_llvm_types[4] == content_llvm_type
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index abf77b4b5fa..1b9605a172c 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -73,14 +73,49 @@ pub fn take_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
     }
 }
 
-pub fn drop_ty<'a>(cx: &'a Block<'a>, v: ValueRef, t: ty::t)
+fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
+    let tcx = ccx.tcx;
+    if !ty::type_needs_drop(tcx, t) {
+        return ty::mk_i8();
+    }
+    match ty::get(t).sty {
+        ty::ty_box(typ) if !ty::type_needs_drop(tcx, typ) =>
+            ty::mk_box(tcx, ty::mk_i8()),
+
+        ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) => {
+            let llty = sizing_type_of(ccx, typ);
+            // Unique boxes do not allocate for zero-size types. The standard library may assume
+            // that `free` is never called on the pointer returned for `~ZeroSizeType`.
+            if llsize_of_alloc(ccx, llty) == 0 {
+                ty::mk_i8()
+            } else {
+                ty::mk_uniq(tcx, ty::mk_i8())
+            }
+        }
+
+        ty::ty_vec(mt, ty::vstore_uniq) if !ty::type_needs_drop(tcx, mt.ty) =>
+            ty::mk_uniq(tcx, ty::mk_i8()),
+
+        _ => t
+    }
+}
+
+pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
                -> &'a Block<'a> {
     // NB: v is an *alias* of type t here, not a direct value.
     let _icx = push_ctxt("drop_ty");
-    if ty::type_needs_drop(cx.tcx(), t) {
-        return call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
+    let ccx = bcx.ccx();
+    if ty::type_needs_drop(bcx.tcx(), t) {
+        let glue = get_drop_glue(ccx, t);
+        let glue_type = get_drop_glue_type(ccx, t);
+        let ptr = if glue_type != t {
+            PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to())
+        } else {
+            v
+        };
+        Call(bcx, glue, [ptr], []);
     }
-    return cx;
+    bcx
 }
 
 pub fn drop_ty_immediate<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
@@ -91,95 +126,49 @@ pub fn drop_ty_immediate<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
     drop_ty(bcx, vp, t)
 }
 
-pub fn lazily_emit_all_tydesc_glue(ccx: @CrateContext,
-                                   static_ti: @tydesc_info) {
-    lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti);
-    lazily_emit_tydesc_glue(ccx, abi::tydesc_field_visit_glue, static_ti);
-}
-
-fn get_glue_type(ccx: &CrateContext, field: uint, t: ty::t) -> ty::t {
-    let tcx = ccx.tcx;
-    if field == abi::tydesc_field_drop_glue {
-        if !ty::type_needs_drop(tcx, t) {
-            return ty::mk_i8();
-        }
-        match ty::get(t).sty {
-            ty::ty_box(typ) if !ty::type_needs_drop(tcx, typ) =>
-                return ty::mk_box(tcx, ty::mk_i8()),
-
-            ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) => {
-                let llty = sizing_type_of(ccx, typ);
-                // Unique boxes do not allocate for zero-size types. The standard library may assume
-                // that `free` is never called on the pointer returned for `~ZeroSizeType`.
-                if llsize_of_alloc(ccx, llty) == 0 {
-                    return ty::mk_i8();
-                } else {
-                    return ty::mk_uniq(tcx, ty::mk_i8());
-                }
-            }
-
-            ty::ty_vec(mt, ty::vstore_uniq) if !ty::type_needs_drop(tcx, mt.ty) =>
-                return ty::mk_uniq(tcx, ty::mk_i8()),
-
-            _ => {}
+pub fn get_drop_glue(ccx: @CrateContext, t: ty::t) -> ValueRef {
+    let t = get_drop_glue_type(ccx, t);
+    {
+        let drop_glues = ccx.drop_glues.borrow();
+        match drop_glues.get().find(&t) {
+            Some(&glue) => return glue,
+            _ => { }
         }
     }
 
-    t
-}
+    let llfnty = Type::glue_fn(type_of(ccx, t).ptr_to());
+    let glue = declare_generic_glue(ccx, t, llfnty, "drop");
 
-pub fn lazily_emit_tydesc_glue(ccx: @CrateContext, field: uint, ti: @tydesc_info) {
-    let _icx = push_ctxt("lazily_emit_tydesc_glue");
+    {
+        let mut drop_glues = ccx.drop_glues.borrow_mut();
+        drop_glues.get().insert(t, glue);
+    }
 
-    let simpl = get_glue_type(ccx, field, ti.ty);
-    if simpl != ti.ty {
-        let _icx = push_ctxt("lazily_emit_simplified_tydesc_glue");
-        let simpl_ti = get_tydesc(ccx, simpl);
-        lazily_emit_tydesc_glue(ccx, field, simpl_ti);
+    make_generic_glue(ccx, t, glue, make_drop_glue, "drop");
 
-        if field == abi::tydesc_field_drop_glue {
-            ti.drop_glue.set(simpl_ti.drop_glue.get());
-        } else if field == abi::tydesc_field_visit_glue {
-            ti.visit_glue.set(simpl_ti.visit_glue.get());
-        }
+    glue
+}
 
-        return;
-    }
+pub fn lazily_emit_visit_glue(ccx: @CrateContext, ti: @tydesc_info) {
+    let _icx = push_ctxt("lazily_emit_visit_glue");
 
     let llfnty = Type::glue_fn(type_of(ccx, ti.ty).ptr_to());
 
-    if field == abi::tydesc_field_drop_glue {
-        match ti.drop_glue.get() {
-          Some(_) => (),
-          None => {
-            debug!("+++ lazily_emit_tydesc_glue DROP {}",
-                   ppaux::ty_to_str(ccx.tcx, ti.ty));
-            let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "drop");
-            ti.drop_glue.set(Some(glue_fn));
-            make_generic_glue(ccx, ti.ty, glue_fn, make_drop_glue, "drop");
-            debug!("--- lazily_emit_tydesc_glue DROP {}",
-                   ppaux::ty_to_str(ccx.tcx, ti.ty));
-          }
-        }
-    } else if field == abi::tydesc_field_visit_glue {
-        match ti.visit_glue.get() {
-          Some(_) => (),
-          None => {
-            debug!("+++ lazily_emit_tydesc_glue VISIT {}",
-                   ppaux::ty_to_str(ccx.tcx, ti.ty));
+    match ti.visit_glue.get() {
+        Some(_) => (),
+        None => {
+            debug!("+++ lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_str(ccx.tcx, ti.ty));
             let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "visit");
             ti.visit_glue.set(Some(glue_fn));
             make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit");
-            debug!("--- lazily_emit_tydesc_glue VISIT {}",
-                   ppaux::ty_to_str(ccx.tcx, ti.ty));
-          }
+            debug!("--- lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_str(ccx.tcx, ti.ty));
         }
     }
 }
 
 // See [Note-arg-mode]
-pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef,
-                             field: uint, static_ti: Option<@tydesc_info>) {
+pub fn call_visit_glue(bcx: &Block, v: ValueRef, tydesc: ValueRef,
+                       static_ti: Option<@tydesc_info>) {
     let _icx = push_ctxt("call_tydesc_glue_full");
     let ccx = bcx.ccx();
     // NB: Don't short-circuit even if this block is unreachable because
@@ -189,37 +178,23 @@ pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef,
     let static_glue_fn = match static_ti {
         None => None,
         Some(sti) => {
-            lazily_emit_tydesc_glue(ccx, field, sti);
-            if field == abi::tydesc_field_drop_glue {
-                sti.drop_glue.get()
-            } else if field == abi::tydesc_field_visit_glue {
-                sti.visit_glue.get()
-            } else {
-                None
-            }
+            lazily_emit_visit_glue(ccx, sti);
+            sti.visit_glue.get()
         }
     };
 
-    // When static type info is available, avoid casting parameter unless the
-    // glue is using a simplified type, because the function already has the
-    // right type. Otherwise cast to generic pointer.
+    // When static type info is available, avoid casting to a generic pointer.
     let llrawptr = if static_glue_fn.is_none() {
         PointerCast(bcx, v, Type::i8p())
     } else {
-        let ty = static_ti.unwrap().ty;
-        let simpl = get_glue_type(ccx, field, ty);
-        if simpl != ty {
-            PointerCast(bcx, v, type_of(ccx, simpl).ptr_to())
-        } else {
-            v
-        }
+        v
     };
 
     let llfn = {
         match static_glue_fn {
             None => {
                 // Select out the glue function to call from the tydesc
-                let llfnptr = GEPi(bcx, tydesc, [0u, field]);
+                let llfnptr = GEPi(bcx, tydesc, [0u, abi::tydesc_field_visit_glue]);
                 Load(bcx, llfnptr)
             }
             Some(sgf) => sgf
@@ -229,15 +204,6 @@ pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef,
     Call(bcx, llfn, [llrawptr], []);
 }
 
-// See [Note-arg-mode]
-fn call_tydesc_glue<'a>(cx: &'a Block<'a>, v: ValueRef, t: ty::t, field: uint)
-                    -> &'a Block<'a> {
-    let _icx = push_ctxt("call_tydesc_glue");
-    let ti = get_tydesc(cx.ccx(), t);
-    call_tydesc_glue_full(cx, v, ti.tydesc, field, Some(ti));
-    cx
-}
-
 fn make_visit_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
                    -> &'a Block<'a> {
     let _icx = push_ctxt("make_visit_glue");
@@ -355,9 +321,9 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
             let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
             // Only drop the value when it is non-null
             with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| {
-                let lldtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
-                let lldtor = Load(bcx, lldtor_ptr);
-                Call(bcx, lldtor, [PointerCast(bcx, lluniquevalue, Type::i8p())], []);
+                let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
+                let dtor = Load(bcx, dtor_ptr);
+                Call(bcx, dtor, [PointerCast(bcx, lluniquevalue, Type::i8p())], []);
                 bcx
             })
         }
@@ -367,18 +333,12 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
             let env_ptr_ty = Type::at_box(ccx, Type::i8()).ptr_to();
             let env = PointerCast(bcx, env, env_ptr_ty);
             with_cond(bcx, IsNotNull(bcx, env), |bcx| {
-                // Load the type descr found in the env
-                let lltydescty = ccx.tydesc_type.ptr_to();
-                let tydescptr = GEPi(bcx, env, [0u, abi::box_field_tydesc]);
-                let tydesc = Load(bcx, tydescptr);
-                let tydesc = PointerCast(bcx, tydesc, lltydescty);
-
-                // Drop the tuple data then free the descriptor
+                let dtor_ptr = GEPi(bcx, env, [0u, abi::box_field_tydesc]);
+                let dtor = Load(bcx, dtor_ptr);
                 let cdata = GEPi(bcx, env, [0u, abi::box_field_body]);
-                call_tydesc_glue_full(bcx, cdata, tydesc,
-                                      abi::tydesc_field_drop_glue, None);
+                Call(bcx, dtor, [PointerCast(bcx, cdata, Type::i8p())], []);
 
-                // Free the ty descr (if necc) and the env itself
+                // Free the environment itself
                 trans_exchange_free(bcx, env)
             })
         }
@@ -468,7 +428,6 @@ pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> @tydesc_info {
         size: llsize,
         align: llalign,
         name: ty_name,
-        drop_glue: Cell::new(None),
         visit_glue: Cell::new(None),
     };
     debug!("--- declare_tydesc {}", ppaux::ty_to_str(ccx.tcx, t));
@@ -520,7 +479,7 @@ fn make_generic_glue(ccx: @CrateContext,
     llfn
 }
 
-pub fn emit_tydescs(ccx: &CrateContext) {
+pub fn emit_tydescs(ccx: @CrateContext) {
     let _icx = push_ctxt("emit_tydescs");
     // As of this point, allow no more tydescs to be created.
     ccx.finished_tydescs.set(true);
@@ -533,21 +492,10 @@ pub fn emit_tydescs(ccx: &CrateContext) {
         // before being put into the tydesc because we only have a singleton
         // tydesc type. Then we'll recast each function to its real type when
         // calling it.
-        let drop_glue =
-            match ti.drop_glue.get() {
-              None => {
-                  ccx.stats.n_null_glues.set(ccx.stats.n_null_glues.get() +
-                                             1u);
-                  C_null(glue_fn_ty)
-              }
-              Some(v) => {
-                unsafe {
-                    ccx.stats.n_real_glues.set(ccx.stats.n_real_glues.get() +
-                                               1);
-                    llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
-                }
-              }
-            };
+        let drop_glue = unsafe {
+            llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref())
+        };
+        ccx.stats.n_real_glues.set(ccx.stats.n_real_glues.get() + 1);
         let visit_glue =
             match ti.visit_glue.get() {
               None => {
diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs
index 49f1b073f87..234b8072dec 100644
--- a/src/librustc/middle/trans/intrinsic.rs
+++ b/src/librustc/middle/trans/intrinsic.rs
@@ -11,7 +11,6 @@
 #[allow(non_uppercase_pattern_statics)];
 
 use arena::TypedArena;
-use back::abi;
 use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg};
 use lib::llvm::{ValueRef, Pointer, Array, Struct};
 use lib;
@@ -326,7 +325,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
         "get_tydesc" => {
             let tp_ty = substs.tys[0];
             let static_ti = get_tydesc(ccx, tp_ty);
-            glue::lazily_emit_all_tydesc_glue(ccx, static_ti);
+            glue::lazily_emit_visit_glue(ccx, static_ti);
 
             // FIXME (#3730): ideally this shouldn't need a cast,
             // but there's a circularity between translating rust types to llvm
@@ -459,8 +458,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
             let td = get_param(decl, first_real_arg);
             let visitor = get_param(decl, first_real_arg + 1u);
             let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to());
-            glue::call_tydesc_glue_full(bcx, visitor, td,
-                                        abi::tydesc_field_visit_glue, None);
+            glue::call_visit_glue(bcx, visitor, td, None);
             RetVoid(bcx);
         }
         "morestack_addr" => {
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index 5d1c67a27ba..4a1ba7b22ac 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -479,11 +479,9 @@ pub fn get_vtable(bcx: &Block,
         }
     });
 
-    // Generate a type descriptor for the vtable.
-    let tydesc = get_tydesc(ccx, self_ty);
-    glue::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, tydesc);
-
-    let vtable = make_vtable(ccx, tydesc, methods);
+    // Generate a destructor for the vtable.
+    let drop_glue = glue::get_drop_glue(ccx, self_ty);
+    let vtable = make_vtable(ccx, drop_glue, methods);
 
     let mut vtables = ccx.vtables.borrow_mut();
     vtables.get().insert(hash_id, vtable);
@@ -492,13 +490,13 @@ pub fn get_vtable(bcx: &Block,
 
 /// Helper function to declare and initialize the vtable.
 pub fn make_vtable(ccx: &CrateContext,
-                   tydesc: &tydesc_info,
+                   drop_glue: ValueRef,
                    ptrs: &[ValueRef])
                    -> ValueRef {
     unsafe {
         let _icx = push_ctxt("meth::make_vtable");
 
-        let mut components = ~[tydesc.drop_glue.get().unwrap()];
+        let mut components = ~[drop_glue];
         for &ptr in ptrs.iter() {
             components.push(ptr)
         }
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index b9d23c47fcd..8c2047a5fc5 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -81,7 +81,7 @@ impl<'a> Reflector<'a> {
     pub fn c_tydesc(&mut self, t: ty::t) -> ValueRef {
         let bcx = self.bcx;
         let static_ti = get_tydesc(bcx.ccx(), t);
-        glue::lazily_emit_all_tydesc_glue(bcx.ccx(), static_ti);
+        glue::lazily_emit_visit_glue(bcx.ccx(), static_ti);
         PointerCast(bcx, static_ti.tydesc, self.tydesc_ty.ptr_to())
     }
 
diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs
index 8eccbf8d956..804486c4159 100644
--- a/src/librustc/middle/trans/type_.rs
+++ b/src/librustc/middle/trans/type_.rs
@@ -238,7 +238,7 @@ impl Type {
     // The box pointed to by @T.
     pub fn at_box(ctx: &CrateContext, ty: Type) -> Type {
         Type::struct_([
-            ctx.int_type, ctx.tydesc_type.ptr_to(),
+            ctx.int_type, Type::glue_fn(Type::i8p()).ptr_to(),
             Type::i8p(), Type::i8p(), ty
         ], false)
     }
diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs
index 82c1ed7440c..a43dca94970 100644
--- a/src/libstd/cleanup.rs
+++ b/src/libstd/cleanup.rs
@@ -11,11 +11,8 @@
 #[doc(hidden)];
 
 use ptr;
-use unstable::intrinsics::TyDesc;
 use unstable::raw;
 
-type DropGlue<'a> = 'a |**TyDesc, *u8|;
-
 static RC_IMMORTAL : uint = 0x77777777;
 
 /*
@@ -24,11 +21,6 @@ static RC_IMMORTAL : uint = 0x77777777;
  * This runs at task death to free all boxes.
  */
 
-struct AnnihilateStats {
-    n_total_boxes: uint,
-    n_bytes_freed: uint
-}
-
 unsafe fn each_live_alloc(read_next_before: bool,
                           f: |alloc: *mut raw::Box<()>| -> bool)
                           -> bool {
@@ -65,21 +57,18 @@ fn debug_mem() -> bool {
 }
 
 /// Destroys all managed memory (i.e. @ boxes) held by the current task.
+#[cfg(stage0)]
 pub unsafe fn annihilate() {
     use rt::local_heap::local_free;
-    use mem;
 
-    let mut stats = AnnihilateStats {
-        n_total_boxes: 0,
-        n_bytes_freed: 0
-    };
+    let mut n_total_boxes = 0u;
 
     // Pass 1: Make all boxes immortal.
     //
     // In this pass, nothing gets freed, so it does not matter whether
     // we read the next field before or after the callback.
     each_live_alloc(true, |alloc| {
-        stats.n_total_boxes += 1;
+        n_total_boxes += 1;
         (*alloc).ref_count = RC_IMMORTAL;
         true
     });
@@ -103,18 +92,58 @@ pub unsafe fn annihilate() {
     // left), so we must read the `next` field before, since it will
     // not be valid after.
     each_live_alloc(true, |alloc| {
-        stats.n_bytes_freed +=
-            (*((*alloc).type_desc)).size
-            + mem::size_of::<raw::Box<()>>();
         local_free(alloc as *u8);
         true
     });
 
     if debug_mem() {
         // We do logging here w/o allocation.
-        debug!("annihilator stats:\n  \
-                       total boxes: {}\n  \
-                       bytes freed: {}",
-                stats.n_total_boxes, stats.n_bytes_freed);
+        debug!("total boxes annihilated: {}", n_total_boxes);
+    }
+}
+
+/// Destroys all managed memory (i.e. @ boxes) held by the current task.
+#[cfg(not(stage0))]
+pub unsafe fn annihilate() {
+    use rt::local_heap::local_free;
+
+    let mut n_total_boxes = 0u;
+
+    // Pass 1: Make all boxes immortal.
+    //
+    // In this pass, nothing gets freed, so it does not matter whether
+    // we read the next field before or after the callback.
+    each_live_alloc(true, |alloc| {
+        n_total_boxes += 1;
+        (*alloc).ref_count = RC_IMMORTAL;
+        true
+    });
+
+    // Pass 2: Drop all boxes.
+    //
+    // In this pass, unique-managed boxes may get freed, but not
+    // managed boxes, so we must read the `next` field *after* the
+    // callback, as the original value may have been freed.
+    each_live_alloc(false, |alloc| {
+        let drop_glue = (*alloc).drop_glue;
+        let data = &mut (*alloc).data as *mut ();
+        drop_glue(data as *mut u8);
+        true
+    });
+
+    // Pass 3: Free all boxes.
+    //
+    // In this pass, managed boxes may get freed (but not
+    // unique-managed boxes, though I think that none of those are
+    // left), so we must read the `next` field before, since it will
+    // not be valid after.
+    each_live_alloc(true, |alloc| {
+        local_free(alloc as *u8);
+        true
+    });
+
+    if debug_mem() {
+        // We do logging here w/o allocation.
+        debug!("total boxes annihilated: {}", n_total_boxes);
     }
 }
diff --git a/src/libstd/rt/env.rs b/src/libstd/rt/env.rs
index 729e377e1af..571ed77592f 100644
--- a/src/libstd/rt/env.rs
+++ b/src/libstd/rt/env.rs
@@ -10,6 +10,8 @@
 
 //! Runtime environment settings
 
+// NOTE: remove `POISON_ON_FREE` after a snapshot
+
 use from_str::from_str;
 use option::{Some, None};
 use os;
diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs
index 6bee8cb70f5..2f553585f38 100644
--- a/src/libstd/rt/global_heap.rs
+++ b/src/libstd/rt/global_heap.rs
@@ -10,7 +10,9 @@
 
 use libc::{c_void, size_t, free, malloc, realloc};
 use ptr::{RawPtr, mut_null};
-use unstable::intrinsics::{TyDesc, abort};
+#[cfg(stage0)]
+use unstable::intrinsics::TyDesc;
+use unstable::intrinsics::abort;
 use unstable::raw;
 use mem::size_of;
 
@@ -73,14 +75,23 @@ pub unsafe fn exchange_malloc(size: uint) -> *u8 {
 }
 
 // FIXME: #7496
-#[cfg(not(test))]
+#[cfg(not(test), stage0)]
 #[lang="closure_exchange_malloc"]
 #[inline]
 pub unsafe fn closure_exchange_malloc_(td: *u8, size: uint) -> *u8 {
     closure_exchange_malloc(td, size)
 }
 
+// FIXME: #7496
+#[cfg(not(test), not(stage0))]
+#[lang="closure_exchange_malloc"]
 #[inline]
+pub unsafe fn closure_exchange_malloc_(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
+    closure_exchange_malloc(drop_glue, size, align)
+}
+
+#[inline]
+#[cfg(stage0)]
 pub unsafe fn closure_exchange_malloc(td: *u8, size: uint) -> *u8 {
     let td = td as *TyDesc;
     let size = size;
@@ -96,6 +107,18 @@ pub unsafe fn closure_exchange_malloc(td: *u8, size: uint) -> *u8 {
     alloc as *u8
 }
 
+#[inline]
+#[cfg(not(stage0))]
+pub unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
+    let total_size = get_box_size(size, align);
+    let p = malloc_raw(total_size);
+
+    let alloc = p as *mut raw::Box<()>;
+    (*alloc).drop_glue = drop_glue;
+
+    alloc as *u8
+}
+
 // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
 // inside a landing pad may corrupt the state of the exception handler.
 #[cfg(not(test))]
diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs
index 79936b4afad..3bee9e48b60 100644
--- a/src/libstd/rt/local_heap.rs
+++ b/src/libstd/rt/local_heap.rs
@@ -21,6 +21,7 @@ use rt::env;
 use rt::global_heap;
 use rt::local::Local;
 use rt::task::Task;
+#[cfg(stage0)]
 use unstable::intrinsics::TyDesc;
 use unstable::raw;
 use vec::ImmutableVector;
@@ -60,6 +61,7 @@ impl LocalHeap {
     }
 
     #[inline]
+    #[cfg(stage0)]
     pub fn alloc(&mut self, td: *TyDesc, size: uint) -> *mut Box {
         let total_size = global_heap::get_box_size(size, unsafe { (*td).align });
         let alloc = self.memory_region.malloc(total_size);
@@ -81,6 +83,28 @@ impl LocalHeap {
     }
 
     #[inline]
+    #[cfg(not(stage0))]
+    pub fn alloc(&mut self, drop_glue: fn(*mut u8), size: uint, align: uint) -> *mut Box {
+        let total_size = global_heap::get_box_size(size, align);
+        let alloc = self.memory_region.malloc(total_size);
+        {
+            // Make sure that we can't use `mybox` outside of this scope
+            let mybox: &mut Box = unsafe { cast::transmute(alloc) };
+            // Clear out this box, and move it to the front of the live
+            // allocations list
+            mybox.drop_glue = drop_glue;
+            mybox.ref_count = 1;
+            mybox.prev = ptr::mut_null();
+            mybox.next = self.live_allocs;
+            if !self.live_allocs.is_null() {
+                unsafe { (*self.live_allocs).prev = alloc; }
+            }
+            self.live_allocs = alloc;
+        }
+        return alloc;
+    }
+
+    #[inline]
     pub fn realloc(&mut self, ptr: *mut Box, size: uint) -> *mut Box {
         // Make sure that we can't use `mybox` outside of this scope
         let total_size = size + mem::size_of::<Box>();
@@ -102,6 +126,7 @@ impl LocalHeap {
     }
 
     #[inline]
+    #[cfg(stage0)]
     pub fn free(&mut self, alloc: *mut Box) {
         {
             // Make sure that we can't use `mybox` outside of this scope
@@ -133,6 +158,28 @@ impl LocalHeap {
 
         self.memory_region.free(alloc);
     }
+
+    #[inline]
+    #[cfg(not(stage0))]
+    pub fn free(&mut self, alloc: *mut Box) {
+        {
+            // Make sure that we can't use `mybox` outside of this scope
+            let mybox: &mut Box = unsafe { cast::transmute(alloc) };
+
+            // Unlink it from the linked list
+            if !mybox.prev.is_null() {
+                unsafe { (*mybox.prev).next = mybox.next; }
+            }
+            if !mybox.next.is_null() {
+                unsafe { (*mybox.next).prev = mybox.prev; }
+            }
+            if self.live_allocs == alloc {
+                self.live_allocs = mybox.next;
+            }
+        }
+
+        self.memory_region.free(alloc);
+    }
 }
 
 impl Drop for LocalHeap {
@@ -292,6 +339,7 @@ impl Drop for MemoryRegion {
 }
 
 #[inline]
+#[cfg(stage0)]
 pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 {
     // FIXME: Unsafe borrow for speed. Lame.
     let task: Option<*mut Task> = Local::try_unsafe_borrow();
@@ -303,6 +351,19 @@ pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 {
     }
 }
 
+#[inline]
+#[cfg(not(stage0))]
+pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
+    // FIXME: Unsafe borrow for speed. Lame.
+    let task: Option<*mut Task> = Local::try_unsafe_borrow();
+    match task {
+        Some(task) => {
+            (*task).heap.alloc(drop_glue, size, align) as *u8
+        }
+        None => rtabort!("local malloc outside of task")
+    }
+}
+
 // A little compatibility function
 #[inline]
 pub unsafe fn local_free(ptr: *u8) {
diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs
index 046d3fc820d..a85f26720bf 100644
--- a/src/libstd/unstable/lang.rs
+++ b/src/libstd/unstable/lang.rs
@@ -27,11 +27,19 @@ pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
 }
 
 #[lang="malloc"]
+#[cfg(stage0)]
 #[inline]
 pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 {
     ::rt::local_heap::local_malloc(td, size)
 }
 
+#[lang="malloc"]
+#[cfg(not(stage0))]
+#[inline]
+pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
+    ::rt::local_heap::local_malloc(drop_glue, size, align)
+}
+
 // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
 // inside a landing pad may corrupt the state of the exception handler. If a
 // problem occurs, call exit instead.
diff --git a/src/libstd/unstable/raw.rs b/src/libstd/unstable/raw.rs
index 63208b3f2d7..98dde95d3b7 100644
--- a/src/libstd/unstable/raw.rs
+++ b/src/libstd/unstable/raw.rs
@@ -9,9 +9,11 @@
 // except according to those terms.
 
 use cast;
+#[cfg(stage0)]
 use unstable::intrinsics::TyDesc;
 
 /// The representation of a Rust managed box
+#[cfg(stage0)]
 pub struct Box<T> {
     ref_count: uint,
     type_desc: *TyDesc,
@@ -20,6 +22,16 @@ pub struct Box<T> {
     data: T
 }
 
+/// The representation of a Rust managed box
+#[cfg(not(stage0))]
+pub struct Box<T> {
+    ref_count: uint,
+    drop_glue: fn(ptr: *mut u8),
+    prev: *mut Box<T>,
+    next: *mut Box<T>,
+    data: T
+}
+
 /// The representation of a Rust vector
 pub struct Vec<T> {
     fill: uint,
@@ -59,9 +71,6 @@ impl<T> Repr<*Box<T>> for @T {}
 impl<T> Repr<*Vec<T>> for ~[T] {}
 impl Repr<*String> for ~str {}
 
-// sure would be nice to have this
-// impl<T> Repr<*Vec<T>> for ~[T] {}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/test/debug-info/basic-types-metadata.rs b/src/test/debug-info/basic-types-metadata.rs
index 0e48b5db7ce..a67279254de 100644
--- a/src/test/debug-info/basic-types-metadata.rs
+++ b/src/test/debug-info/basic-types-metadata.rs
@@ -45,7 +45,7 @@
 // debugger:whatis f64
 // check:type = f64
 // debugger:info functions _yyy
-// check:[...]![...]_yyy()();
+// check:[...]![...]_yyy([...])([...]);
 // debugger:detach
 // debugger:quit