about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-05-10 23:21:44 -0700
committerbors <bors@rust-lang.org>2014-05-10 23:21:44 -0700
commitadb8b0b230d5e5c79b4f873825b3d3cff8d1bc8f (patch)
tree770b50ee78ec3b79feeaf70f73f50f1166bed980 /src
parent11571cd9c1cde63c3b46ca65e608b84647785ac8 (diff)
parent81fadbbc4182c5a34e0d2ff698471abfc1ec0e33 (diff)
auto merge of #14006 : thestinger/rust/jemalloc, r=alexcrichton
Closes #11807
Diffstat (limited to 'src')
m---------src/jemalloc0
-rw-r--r--src/libarena/lib.rs33
-rw-r--r--src/libcollections/hashmap.rs4
-rw-r--r--src/libcore/should_not_exist.rs28
-rw-r--r--src/libnative/io/file_win32.rs2
-rw-r--r--src/librustc/middle/trans/base.rs5
-rw-r--r--src/librustc/middle/trans/expr.rs5
-rw-r--r--src/librustc/middle/trans/tvec.rs4
-rw-r--r--src/librustuv/uvll.rs2
-rw-r--r--src/libstd/c_str.rs2
-rw-r--r--src/libstd/c_vec.rs2
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libstd/rc.rs9
-rw-r--r--src/libstd/rt/global_heap.rs139
-rw-r--r--src/libstd/rt/heap.rs222
-rw-r--r--src/libstd/rt/libc_heap.rs51
-rw-r--r--src/libstd/rt/local_heap.rs12
-rw-r--r--src/libstd/rt/mod.rs11
-rw-r--r--src/libstd/rt/util.rs17
-rw-r--r--src/libstd/slice.rs60
-rw-r--r--src/libstd/unstable/mutex.rs2
-rw-r--r--src/libstd/vec.rs89
-rw-r--r--src/libsync/arc.rs9
23 files changed, 499 insertions, 210 deletions
diff --git a/src/jemalloc b/src/jemalloc
new file mode 160000
+Subproject 6a96910f2eaea6d2c705bb12379b23576b30d7d
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 24e7a65e02a..526b72e9b86 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -33,10 +33,11 @@ use std::cmp;
 use std::intrinsics::{TyDesc, get_tydesc};
 use std::intrinsics;
 use std::mem;
+use std::mem::min_align_of;
 use std::num;
 use std::ptr::read;
 use std::rc::Rc;
-use std::rt::global_heap;
+use std::rt::heap::exchange_malloc;
 
 // The way arena uses arrays is really deeply awful. The arrays are
 // allocated, and have capacities reserved, but the fill for the array
@@ -204,7 +205,7 @@ impl Arena {
     #[inline]
     fn alloc_copy<'a, T>(&'a mut self, op: || -> T) -> &'a T {
         unsafe {
-            let ptr = self.alloc_copy_inner(mem::size_of::<T>(), mem::min_align_of::<T>());
+            let ptr = self.alloc_copy_inner(mem::size_of::<T>(), min_align_of::<T>());
             let ptr: *mut T = transmute(ptr);
             mem::move_val_init(&mut (*ptr), op());
             return transmute(ptr);
@@ -261,7 +262,7 @@ impl Arena {
         unsafe {
             let tydesc = get_tydesc::<T>();
             let (ty_ptr, ptr) =
-                self.alloc_noncopy_inner(mem::size_of::<T>(), mem::min_align_of::<T>());
+                self.alloc_noncopy_inner(mem::size_of::<T>(), 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
@@ -353,17 +354,39 @@ struct TypedArenaChunk<T> {
 }
 
 impl<T> TypedArenaChunk<T> {
+    #[cfg(stage0)]
     #[inline]
     fn new(next: Option<Box<TypedArenaChunk<T>>>, capacity: uint)
            -> Box<TypedArenaChunk<T>> {
         let mut size = mem::size_of::<TypedArenaChunk<T>>();
+        size = round_up(size, min_align_of::<T>());
+        let elem_size = mem::size_of::<T>();
+        let elems_size = elem_size.checked_mul(&capacity).unwrap();
+        size = size.checked_add(&elems_size).unwrap();
+
+        let mut chunk = unsafe {
+            let chunk = exchange_malloc(size);
+            let mut chunk: Box<TypedArenaChunk<T>> = cast::transmute(chunk);
+            mem::move_val_init(&mut chunk.next, next);
+            chunk
+        };
+
+        chunk.capacity = capacity;
+        chunk
+    }
+
+    #[inline]
+    #[cfg(not(stage0))]
+    fn new(next: Option<Box<TypedArenaChunk<T>>>, capacity: uint)
+           -> Box<TypedArenaChunk<T>> {
+        let mut size = mem::size_of::<TypedArenaChunk<T>>();
         size = round_up(size, mem::min_align_of::<T>());
         let elem_size = mem::size_of::<T>();
         let elems_size = elem_size.checked_mul(&capacity).unwrap();
         size = size.checked_add(&elems_size).unwrap();
 
         let mut chunk = unsafe {
-            let chunk = global_heap::exchange_malloc(size);
+            let chunk = exchange_malloc(size, min_align_of::<TypedArenaChunk<T>>());
             let mut chunk: Box<TypedArenaChunk<T>> = cast::transmute(chunk);
             mem::move_val_init(&mut chunk.next, next);
             chunk
@@ -402,7 +425,7 @@ impl<T> TypedArenaChunk<T> {
     fn start(&self) -> *u8 {
         let this: *TypedArenaChunk<T> = self;
         unsafe {
-            cast::transmute(round_up(this.offset(1) as uint, mem::min_align_of::<T>()))
+            cast::transmute(round_up(this.offset(1) as uint, min_align_of::<T>()))
         }
     }
 
diff --git a/src/libcollections/hashmap.rs b/src/libcollections/hashmap.rs
index 2d1de87fe06..1a222a27e47 100644
--- a/src/libcollections/hashmap.rs
+++ b/src/libcollections/hashmap.rs
@@ -42,7 +42,7 @@ mod table {
     use std::prelude::Drop;
     use std::ptr;
     use std::ptr::RawPtr;
-    use std::rt::global_heap;
+    use std::rt::libc_heap;
     use std::intrinsics::{size_of, min_align_of, transmute};
     use std::intrinsics::{move_val_init, set_memory};
     use std::iter::{Iterator, range_step_inclusive};
@@ -243,7 +243,7 @@ mod table {
                     keys_size,   min_align_of::< K >(),
                     vals_size,   min_align_of::< V >());
 
-            let buffer = global_heap::malloc_raw(size) as *mut u8;
+            let buffer = libc_heap::malloc_raw(size) as *mut u8;
 
             // FIXME #13094: If malloc was not at as aligned as we expected,
             // our offset calculations are just plain wrong. We could support
diff --git a/src/libcore/should_not_exist.rs b/src/libcore/should_not_exist.rs
index 0e6baaa518a..f199aa051d1 100644
--- a/src/libcore/should_not_exist.rs
+++ b/src/libcore/should_not_exist.rs
@@ -29,13 +29,30 @@ use str::StrSlice;
 
 #[allow(ctypes)]
 extern {
-    fn malloc(size: uint) -> *u8;
-    fn free(ptr: *u8);
+    #[cfg(stage0)]
+    fn rust_malloc(size: uint) -> *u8;
+    #[cfg(not(stage0))]
+    fn rust_malloc(size: uint, align: uint) -> *u8;
+    fn rust_free(ptr: *u8, size: uint, align: uint);
 }
 
+#[cfg(stage0)]
 unsafe fn alloc(cap: uint) -> *mut Vec<()> {
     let cap = cap.checked_add(&mem::size_of::<Vec<()>>()).unwrap();
-    let ret = malloc(cap) as *mut Vec<()>;
+    let ret = rust_malloc(cap) as *mut Vec<()>;
+    if ret.is_null() {
+        intrinsics::abort();
+    }
+    (*ret).fill = 0;
+    (*ret).alloc = cap;
+    ret
+}
+
+#[cfg(not(stage0))]
+unsafe fn alloc(cap: uint) -> *mut Vec<()> {
+    let cap = cap.checked_add(&mem::size_of::<Vec<()>>()).unwrap();
+    // this should use the real alignment, but the new representation will take care of that
+    let ret = rust_malloc(cap, 8) as *mut Vec<()>;
     if ret.is_null() {
         intrinsics::abort();
     }
@@ -102,7 +119,8 @@ impl FromIterator<char> for ~str {
                     ptr::copy_nonoverlapping_memory(&mut (*ptr2).data,
                                                     &(*ptr).data,
                                                     len);
-                    free(ptr as *u8);
+                    // FIXME: #13994: port to the sized deallocation API when available
+                    rust_free(ptr as *u8, 0, 8);
                     cast::forget(ret);
                     ret = cast::transmute(ptr2);
                     ptr = ptr2;
@@ -172,7 +190,7 @@ impl<A: Clone> Clone for ~[A] {
                     for j in range(0, *i as int) {
                         ptr::read(&*p.offset(j));
                     }
-                    free(ret as *u8);
+                    rust_free(ret as *u8, 0, 8);
                 });
             cast::transmute(ret)
         }
diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs
index 42e5ad062ee..5fc9e506cf2 100644
--- a/src/libnative/io/file_win32.rs
+++ b/src/libnative/io/file_win32.rs
@@ -339,7 +339,7 @@ pub fn mkdir(p: &CString, _mode: io::FilePermission) -> IoResult<()> {
 }
 
 pub fn readdir(p: &CString) -> IoResult<Vec<Path>> {
-    use std::rt::global_heap::malloc_raw;
+    use std::rt::libc_heap::malloc_raw;
 
     fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
         let root = unsafe { CString::new(root.with_ref(|p| p), false) };
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 6c4566c09aa..8f878f099fc 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -345,7 +345,8 @@ fn require_alloc_fn(bcx: &Block, info_ty: ty::t, it: LangItem) -> ast::DefId {
 
 pub fn malloc_raw_dyn<'a>(bcx: &'a Block<'a>,
                           ptr_ty: ty::t,
-                          size: ValueRef)
+                          size: ValueRef,
+                          align: ValueRef)
                           -> Result<'a> {
     let _icx = push_ctxt("malloc_raw_exchange");
     let ccx = bcx.ccx();
@@ -353,7 +354,7 @@ pub fn malloc_raw_dyn<'a>(bcx: &'a Block<'a>,
     // Allocate space:
     let r = callee::trans_lang_call(bcx,
         require_alloc_fn(bcx, ptr_ty, ExchangeMallocFnLangItem),
-        [size],
+        [size, align],
         None);
 
     let llty_ptr = type_of::type_of(ccx, ptr_ty);
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 806fb3e125d..463aa67ac90 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -67,7 +67,7 @@ use middle::typeck::MethodCall;
 use util::common::indenter;
 use util::ppaux::Repr;
 use util::nodemap::NodeMap;
-use middle::trans::machine::{llsize_of, llsize_of_alloc};
+use middle::trans::machine::{llalign_of_min, llsize_of, llsize_of_alloc};
 use middle::trans::type_::Type;
 
 use syntax::ast;
@@ -1170,10 +1170,11 @@ fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
     let fcx = bcx.fcx;
     let llty = type_of::type_of(bcx.ccx(), contents_ty);
     let size = llsize_of(bcx.ccx(), llty);
+    let align = C_uint(bcx.ccx(), llalign_of_min(bcx.ccx(), llty) as uint);
     // We need to a make a pointer type because box_ty is ty_bot
     // if content_ty is, e.g. box fail!().
     let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty);
-    let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size);
+    let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size, align);
     // Unique boxes do not allocate for zero-size types. The standard library
     // may assume that `free` is never called on the pointer returned for
     // `Box<ZeroSizeType>`.
diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs
index e210437a370..48179abc052 100644
--- a/src/librustc/middle/trans/tvec.rs
+++ b/src/librustc/middle/trans/tvec.rs
@@ -278,7 +278,9 @@ pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>,
 
     let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));
 
-    let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize);
+    // ~[T] is not going to be changed to support alignment, since it's obsolete.
+    let align = C_uint(ccx, 8);
+    let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize, align);
     Store(bcx, fill, GEPi(bcx, val, [0u, abi::vec_elt_fill]));
     Store(bcx, alloc, GEPi(bcx, val, [0u, abi::vec_elt_alloc]));
 
diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs
index 57f4bd9d7eb..6236fd0e0e5 100644
--- a/src/librustuv/uvll.rs
+++ b/src/librustuv/uvll.rs
@@ -32,7 +32,7 @@
 use libc::{size_t, c_int, c_uint, c_void, c_char, c_double};
 use libc::{ssize_t, sockaddr, free, addrinfo};
 use libc;
-use std::rt::global_heap::malloc_raw;
+use std::rt::libc_heap::malloc_raw;
 
 #[cfg(test)]
 use libc::uintptr_t;
diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs
index 7de74dbe507..b33d211aa19 100644
--- a/src/libstd/c_str.rs
+++ b/src/libstd/c_str.rs
@@ -81,7 +81,7 @@ use str::StrSlice;
 use str;
 use slice::{ImmutableVector, MutableVector};
 use slice;
-use rt::global_heap::malloc_raw;
+use rt::libc_heap::malloc_raw;
 use raw::Slice;
 
 /// The representation of a C String.
diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs
index 4ef5af9275c..8c2c4fd1f0b 100644
--- a/src/libstd/c_vec.rs
+++ b/src/libstd/c_vec.rs
@@ -160,7 +160,7 @@ mod tests {
     use super::CVec;
     use libc;
     use ptr;
-    use rt::global_heap::malloc_raw;
+    use rt::libc_heap::malloc_raw;
 
     fn malloc(n: uint) -> CVec<u8> {
         unsafe {
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 0ac6f1dba4f..3f22a76c1f4 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -110,6 +110,7 @@
 // Don't link to std. We are std.
 #![no_std]
 
+#![allow(deprecated)]
 #![deny(missing_doc)]
 
 // When testing libstd, bring in libuv as the I/O backend so tests can print
diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs
index 51ab885a85f..e0fe75fd907 100644
--- a/src/libstd/rc.rs
+++ b/src/libstd/rc.rs
@@ -32,7 +32,8 @@ use ops::{Deref, Drop};
 use option::{Option, Some, None};
 use ptr;
 use ptr::RawPtr;
-use rt::global_heap::exchange_free;
+use mem::{min_align_of, size_of};
+use rt::heap::exchange_free;
 
 struct RcBox<T> {
     value: T,
@@ -104,7 +105,8 @@ impl<T> Drop for Rc<T> {
                     self.dec_weak();
 
                     if self.weak() == 0 {
-                        exchange_free(self.ptr as *u8)
+                        exchange_free(self.ptr as *mut u8, size_of::<RcBox<T>>(),
+                                      min_align_of::<RcBox<T>>())
                     }
                 }
             }
@@ -177,7 +179,8 @@ impl<T> Drop for Weak<T> {
                 // the weak count starts at 1, and will only go to
                 // zero if all the strong pointers have disappeared.
                 if self.weak() == 0 {
-                    exchange_free(self.ptr as *u8)
+                    exchange_free(self.ptr as *mut u8, size_of::<RcBox<T>>(),
+                                  min_align_of::<RcBox<T>>())
                 }
             }
         }
diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs
deleted file mode 100644
index 7d54c3faf42..00000000000
--- a/src/libstd/rt/global_heap.rs
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-//! The global (exchange) heap.
-
-use libc::{c_void, size_t, free, malloc, realloc};
-use ptr::{RawPtr, mut_null};
-use intrinsics::abort;
-use raw;
-use mem::size_of;
-
-#[inline]
-pub fn get_box_size(body_size: uint, body_align: uint) -> uint {
-    let header_size = size_of::<raw::Box<()>>();
-    let total_size = align_to(header_size, body_align) + body_size;
-    total_size
-}
-
-// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power
-// of two.
-#[inline]
-fn align_to(size: uint, align: uint) -> uint {
-    assert!(align != 0);
-    (size + align - 1) & !(align - 1)
-}
-
-/// A wrapper around libc::malloc, aborting on out-of-memory
-#[inline]
-pub unsafe fn malloc_raw(size: uint) -> *mut u8 {
-    // `malloc(0)` may allocate, but it may also return a null pointer
-    // http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html
-    if size == 0 {
-        mut_null()
-    } else {
-        let p = malloc(size as size_t);
-        if p.is_null() {
-            // we need a non-allocating way to print an error here
-            abort();
-        }
-        p as *mut u8
-    }
-}
-
-/// A wrapper around libc::realloc, aborting on out-of-memory
-#[inline]
-pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 {
-    // `realloc(ptr, 0)` may allocate, but it may also return a null pointer
-    // http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html
-    if size == 0 {
-        free(ptr as *mut c_void);
-        mut_null()
-    } else {
-        let p = realloc(ptr as *mut c_void, size as size_t);
-        if p.is_null() {
-            // we need a non-allocating way to print an error here
-            abort();
-        }
-        p as *mut u8
-    }
-}
-
-/// The allocator for unique pointers without contained managed pointers.
-#[cfg(not(test))]
-#[lang="exchange_malloc"]
-#[inline]
-pub unsafe fn exchange_malloc(size: uint) -> *mut u8 {
-    // The compiler never calls `exchange_free` on Box<ZeroSizeType>, so
-    // zero-size allocations can point to this `static`. It would be incorrect
-    // to use a null pointer, due to enums assuming types like unique pointers
-    // are never null.
-    static EMPTY: () = ();
-
-    if size == 0 {
-        &EMPTY as *() as *mut u8
-    } else {
-        malloc_raw(size)
-    }
-}
-
-// FIXME: #7496
-#[cfg(not(test))]
-#[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]
-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))]
-#[lang="exchange_free"]
-#[inline]
-pub unsafe fn exchange_free_(ptr: *u8) {
-    exchange_free(ptr)
-}
-
-#[inline]
-pub unsafe fn exchange_free(ptr: *u8) {
-    free(ptr as *mut c_void);
-}
-
-#[cfg(test)]
-mod bench {
-    extern crate test;
-    use self::test::Bencher;
-
-    #[bench]
-    fn alloc_owned_small(b: &mut Bencher) {
-        b.iter(|| {
-            box 10
-        })
-    }
-
-    #[bench]
-    fn alloc_owned_big(b: &mut Bencher) {
-        b.iter(|| {
-            box [10, ..1000]
-        })
-    }
-}
diff --git a/src/libstd/rt/heap.rs b/src/libstd/rt/heap.rs
new file mode 100644
index 00000000000..ffe6dccfa15
--- /dev/null
+++ b/src/libstd/rt/heap.rs
@@ -0,0 +1,222 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// FIXME: #13994: port to the sized deallocation API when available
+// FIXME: #13996: need a way to mark the `allocate` and `reallocate` return values as `noalias`
+
+use intrinsics::{abort, cttz32};
+use libc::{c_int, c_void, size_t};
+use ptr::RawPtr;
+
+#[link(name = "jemalloc", kind = "static")]
+extern {
+    fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
+    fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
+    fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
+    fn je_dallocx(ptr: *mut c_void, flags: c_int);
+    fn je_nallocx(size: size_t, flags: c_int) -> size_t;
+}
+
+// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
+#[cfg(not(windows), not(target_os = "android"))]
+#[link(name = "pthread")]
+extern {}
+
+// MALLOCX_ALIGN(a) macro
+#[inline(always)]
+fn mallocx_align(a: uint) -> c_int { unsafe { cttz32(a as u32) as c_int } }
+
+/// Return a pointer to `size` bytes of memory.
+///
+/// Behavior is undefined if the requested size is 0 or the alignment is not a power of 2. The
+/// alignment must be no larger than the largest supported page size on the platform.
+#[inline]
+pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
+    let ptr = je_mallocx(size as size_t, mallocx_align(align)) as *mut u8;
+    if ptr.is_null() {
+        abort()
+    }
+    ptr
+}
+
+/// Extend or shrink the allocation referenced by `ptr` to `size` bytes of memory.
+///
+/// Behavior is undefined if the requested size is 0 or the alignment is not a power of 2. The
+/// alignment must be no larger than the largest supported page size on the platform.
+///
+/// The `old_size` and `align` parameters are the parameters that were used to create the
+/// allocation referenced by `ptr`. The `old_size` parameter may also be the value returned by
+/// `usable_size` for the requested size.
+#[inline]
+#[allow(unused_variable)] // for the parameter names in the documentation
+pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint, old_size: uint) -> *mut u8 {
+    let ptr = je_rallocx(ptr as *mut c_void, size as size_t, mallocx_align(align)) as *mut u8;
+    if ptr.is_null() {
+        abort()
+    }
+    ptr
+}
+
+/// Extend or shrink the allocation referenced by `ptr` to `size` bytes of memory in-place.
+///
+/// Return true if successful, otherwise false if the allocation was not altered.
+///
+/// Behavior is undefined if the requested size is 0 or the alignment is not a power of 2. The
+/// alignment must be no larger than the largest supported page size on the platform.
+///
+/// The `old_size` and `align` parameters are the parameters that were used to
+/// create the allocation referenced by `ptr`. The `old_size` parameter may be
+/// any value in range_inclusive(requested_size, usable_size).
+#[inline]
+#[allow(unused_variable)] // for the parameter names in the documentation
+pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint, old_size: uint) -> bool {
+    je_xallocx(ptr as *mut c_void, size as size_t, 0, mallocx_align(align)) == size as size_t
+}
+
+/// Deallocate the memory referenced by `ptr`.
+///
+/// The `ptr` parameter must not be null.
+///
+/// The `size` and `align` parameters are the parameters that were used to create the
+/// allocation referenced by `ptr`. The `size` parameter may also be the value returned by
+/// `usable_size` for the requested size.
+#[inline]
+#[allow(unused_variable)] // for the parameter names in the documentation
+pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
+    je_dallocx(ptr as *mut c_void, mallocx_align(align))
+}
+
+/// Return the usable size of an allocation created with the specified the `size` and `align`.
+#[inline]
+pub fn usable_size(size: uint, align: uint) -> uint {
+    unsafe { je_nallocx(size as size_t, mallocx_align(align)) as uint }
+}
+
+/// The allocator for unique pointers.
+#[cfg(stage0)]
+#[lang="exchange_malloc"]
+#[inline(always)]
+pub unsafe fn exchange_malloc_(size: uint) -> *mut u8 {
+    exchange_malloc(size)
+}
+
+/// The allocator for unique pointers.
+#[cfg(not(test), not(stage0))]
+#[lang="exchange_malloc"]
+#[inline(always)]
+pub unsafe fn exchange_malloc_(size: uint, align: uint) -> *mut u8 {
+    exchange_malloc(size, align)
+}
+
+/// The allocator for unique pointers.
+#[cfg(stage0)]
+#[inline]
+pub unsafe fn exchange_malloc(size: uint) -> *mut u8 {
+    // The compiler never calls `exchange_free` on ~ZeroSizeType, so zero-size
+    // allocations can point to this `static`. It would be incorrect to use a null
+    // pointer, due to enums assuming types like unique pointers are never null.
+    static EMPTY: () = ();
+
+    if size == 0 {
+        &EMPTY as *() as *mut u8
+    } else {
+        allocate(size, 8)
+    }
+}
+
+/// The allocator for unique pointers.
+#[cfg(not(stage0))]
+#[inline]
+pub unsafe fn exchange_malloc(size: uint, align: uint) -> *mut u8 {
+    // The compiler never calls `exchange_free` on ~ZeroSizeType, so zero-size
+    // allocations can point to this `static`. It would be incorrect to use a null
+    // pointer, due to enums assuming types like unique pointers are never null.
+    static EMPTY: () = ();
+
+    if size == 0 {
+        &EMPTY as *() as *mut u8
+    } else {
+        allocate(size, align)
+    }
+}
+
+#[cfg(not(test))]
+#[lang="exchange_free"]
+#[inline]
+// FIXME: #13994 (rustc should pass align and size here)
+pub unsafe fn exchange_free_(ptr: *mut u8) {
+    exchange_free(ptr, 0, 8)
+}
+
+#[inline]
+pub unsafe fn exchange_free(ptr: *mut u8, size: uint, align: uint) {
+    deallocate(ptr, size, align);
+}
+
+// FIXME: #7496
+#[cfg(not(test))]
+#[lang="closure_exchange_malloc"]
+#[inline]
+unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *mut u8 {
+    let total_size = ::rt::util::get_box_size(size, align);
+    let p = allocate(total_size, 8);
+
+    let alloc = p as *mut ::raw::Box<()>;
+    (*alloc).drop_glue = drop_glue;
+
+    alloc as *mut u8
+}
+
+// hack for libcore
+#[no_mangle]
+#[doc(hidden)]
+#[deprecated]
+#[cfg(stage0, not(test))]
+pub extern "C" fn rust_malloc(size: uint) -> *mut u8 {
+    unsafe { exchange_malloc(size) }
+}
+
+// hack for libcore
+#[no_mangle]
+#[doc(hidden)]
+#[deprecated]
+#[cfg(not(stage0), not(test))]
+pub extern "C" fn rust_malloc(size: uint, align: uint) -> *mut u8 {
+    unsafe { exchange_malloc(size, align) }
+}
+
+// hack for libcore
+#[no_mangle]
+#[doc(hidden)]
+#[deprecated]
+#[cfg(not(test))]
+pub extern "C" fn rust_free(ptr: *mut u8, size: uint, align: uint) {
+    unsafe { exchange_free(ptr, size, align) }
+}
+
+#[cfg(test)]
+mod bench {
+    extern crate test;
+    use self::test::Bencher;
+
+    #[bench]
+    fn alloc_owned_small(b: &mut Bencher) {
+        b.iter(|| {
+            box 10
+        })
+    }
+
+    #[bench]
+    fn alloc_owned_big(b: &mut Bencher) {
+        b.iter(|| {
+            box [10, ..1000]
+        })
+    }
+}
diff --git a/src/libstd/rt/libc_heap.rs b/src/libstd/rt/libc_heap.rs
new file mode 100644
index 00000000000..ece51ab9989
--- /dev/null
+++ b/src/libstd/rt/libc_heap.rs
@@ -0,0 +1,51 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+//! The global (exchange) heap.
+
+use libc::{c_void, size_t, free, malloc, realloc};
+use ptr::{RawPtr, mut_null};
+use intrinsics::abort;
+
+/// A wrapper around libc::malloc, aborting on out-of-memory
+#[inline]
+pub unsafe fn malloc_raw(size: uint) -> *mut u8 {
+    // `malloc(0)` may allocate, but it may also return a null pointer
+    // http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html
+    if size == 0 {
+        mut_null()
+    } else {
+        let p = malloc(size as size_t);
+        if p.is_null() {
+            // we need a non-allocating way to print an error here
+            abort();
+        }
+        p as *mut u8
+    }
+}
+
+/// A wrapper around libc::realloc, aborting on out-of-memory
+#[inline]
+pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 {
+    // `realloc(ptr, 0)` may allocate, but it may also return a null pointer
+    // http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html
+    if size == 0 {
+        free(ptr as *mut c_void);
+        mut_null()
+    } else {
+        let p = realloc(ptr as *mut c_void, size as size_t);
+        if p.is_null() {
+            // we need a non-allocating way to print an error here
+            abort();
+        }
+        p as *mut u8
+    }
+}
diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs
index caf0d9028c5..efc8072594b 100644
--- a/src/libstd/rt/local_heap.rs
+++ b/src/libstd/rt/local_heap.rs
@@ -12,12 +12,13 @@
 
 use cast;
 use iter::Iterator;
+use libc::{c_void, free};
 use mem;
 use ops::Drop;
 use option::{Option, None, Some};
 use ptr;
 use ptr::RawPtr;
-use rt::global_heap;
+use rt::libc_heap;
 use rt::local::Local;
 use rt::task::Task;
 use raw;
@@ -58,7 +59,7 @@ impl LocalHeap {
 
     #[inline]
     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 total_size = ::rt::util::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
@@ -187,7 +188,7 @@ impl MemoryRegion {
     fn malloc(&mut self, size: uint) -> *mut Box {
         let total_size = size + AllocHeader::size();
         let alloc: *AllocHeader = unsafe {
-            global_heap::malloc_raw(total_size) as *AllocHeader
+            libc_heap::malloc_raw(total_size) as *AllocHeader
         };
 
         let alloc: &mut AllocHeader = unsafe { cast::transmute(alloc) };
@@ -206,8 +207,7 @@ impl MemoryRegion {
 
         let total_size = size + AllocHeader::size();
         let alloc: *AllocHeader = unsafe {
-            global_heap::realloc_raw(orig_alloc as *mut u8,
-                                     total_size) as *AllocHeader
+            libc_heap::realloc_raw(orig_alloc as *mut u8, total_size) as *AllocHeader
         };
 
         let alloc: &mut AllocHeader = unsafe { cast::transmute(alloc) };
@@ -226,7 +226,7 @@ impl MemoryRegion {
             self.release(cast::transmute(alloc));
             rtassert!(self.live_allocations > 0);
             self.live_allocations -= 1;
-            global_heap::exchange_free(alloc as *u8)
+            free(alloc as *mut c_void)
         }
     }
 
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 5b9c314d42b..a04cbabedd6 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -26,7 +26,7 @@ language and an implementation must be provided regardless of the
 execution environment.
 
 Of foremost importance is the global exchange heap, in the module
-`global_heap`. Very little practical Rust code can be written without
+`heap`. Very little practical Rust code can be written without
 access to the global heap. Unlike most of `rt` the global heap is
 truly a global resource and generally operates independently of the
 rest of the runtime.
@@ -86,10 +86,13 @@ pub mod shouldnt_be_public {
 // Internal macros used by the runtime.
 mod macros;
 
-// The global (exchange) heap.
-pub mod global_heap;
+/// Wrappers around malloc / realloc aborting on out-of-memory.
+pub mod libc_heap;
 
-// Implementations of language-critical runtime features like @.
+/// The low-level memory allocation API.
+pub mod heap;
+
+/// Implementations of language-critical runtime features like @.
 pub mod task;
 
 // The EventLoop and internal synchronous I/O interface.
diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs
index 84284ca1faf..e8b1acb1024 100644
--- a/src/libstd/rt/util.rs
+++ b/src/libstd/rt/util.rs
@@ -26,6 +26,23 @@ use slice::ImmutableVector;
 // FIXME: Once the runtime matures remove the `true` below to turn off rtassert, etc.
 pub static ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) || cfg!(rtassert);
 
+#[deprecated]
+#[doc(hidden)]
+#[inline]
+pub fn get_box_size(body_size: uint, body_align: uint) -> uint {
+    let header_size = ::mem::size_of::<::raw::Box<()>>();
+    let total_size = align_to(header_size, body_align) + body_size;
+    total_size
+}
+
+// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power
+// of two.
+#[inline]
+fn align_to(size: uint, align: uint) -> uint {
+    assert!(align != 0);
+    (size + align - 1) & !(align - 1)
+}
+
 /// Get the number of cores available
 pub fn num_cpus() -> uint {
     unsafe {
diff --git a/src/libstd/slice.rs b/src/libstd/slice.rs
index 21084407b8d..b97c55ad701 100644
--- a/src/libstd/slice.rs
+++ b/src/libstd/slice.rs
@@ -110,7 +110,7 @@ use ops::Drop;
 use option::{None, Option, Some};
 use ptr::RawPtr;
 use ptr;
-use rt::global_heap::{exchange_free};
+use rt::heap::{exchange_malloc, exchange_free};
 use unstable::finally::try_finally;
 use vec::Vec;
 
@@ -292,9 +292,9 @@ pub trait CloneableVector<T> {
 impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
     /// Returns a copy of `v`.
     #[inline]
+    #[cfg(stage0)]
     fn to_owned(&self) -> ~[T] {
         use RawVec = core::raw::Vec;
-        use rt::global_heap::{malloc_raw, exchange_free};
         use num::{CheckedAdd, CheckedMul};
         use option::Expect;
 
@@ -305,7 +305,8 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
         let size = size.expect("overflow in to_owned()");
 
         unsafe {
-            let ret = malloc_raw(size) as *mut RawVec<()>;
+            // this should pass the real required alignment
+            let ret = exchange_malloc(size) as *mut RawVec<()>;
 
             (*ret).fill = len * mem::nonzero_size_of::<T>();
             (*ret).alloc = len * mem::nonzero_size_of::<T>();
@@ -329,7 +330,55 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
                     for j in range(0, *i as int) {
                         ptr::read(&*p.offset(j));
                     }
-                    exchange_free(ret as *u8);
+                    // FIXME: #13994 (should pass align and size here)
+                    exchange_free(ret as *mut u8, 0, 8);
+                });
+            cast::transmute(ret)
+        }
+    }
+
+    /// Returns a copy of `v`.
+    #[inline]
+    #[cfg(not(stage0))]
+    fn to_owned(&self) -> ~[T] {
+        use RawVec = core::raw::Vec;
+        use num::{CheckedAdd, CheckedMul};
+        use option::Expect;
+
+        let len = self.len();
+        let data_size = len.checked_mul(&mem::size_of::<T>());
+        let data_size = data_size.expect("overflow in to_owned()");
+        let size = mem::size_of::<RawVec<()>>().checked_add(&data_size);
+        let size = size.expect("overflow in to_owned()");
+
+        unsafe {
+            // this should pass the real required alignment
+            let ret = exchange_malloc(size, 8) as *mut RawVec<()>;
+
+            (*ret).fill = len * mem::nonzero_size_of::<T>();
+            (*ret).alloc = len * mem::nonzero_size_of::<T>();
+
+            // Be careful with the following loop. We want it to be optimized
+            // to a memcpy (or something similarly fast) when T is Copy. LLVM
+            // is easily confused, so any extra operations during the loop can
+            // prevent this optimization.
+            let mut i = 0;
+            let p = &mut (*ret).data as *mut _ as *mut T;
+            try_finally(
+                &mut i, (),
+                |i, ()| while *i < len {
+                    mem::move_val_init(
+                        &mut(*p.offset(*i as int)),
+                        self.unsafe_ref(*i).clone());
+                    *i += 1;
+                },
+                |i| if *i < len {
+                    // we must be failing, clean up after ourselves
+                    for j in range(0, *i as int) {
+                        ptr::read(&*p.offset(j));
+                    }
+                    // FIXME: #13994 (should pass align and size here)
+                    exchange_free(ret as *mut u8, 0, 8);
                 });
             cast::transmute(ret)
         }
@@ -768,7 +817,8 @@ impl<T> Drop for MoveItems<T> {
         // destroy the remaining elements
         for _x in *self {}
         unsafe {
-            exchange_free(self.allocation as *u8)
+            // FIXME: #13994 (should pass align and size here)
+            exchange_free(self.allocation, 0, 8)
         }
     }
 }
diff --git a/src/libstd/unstable/mutex.rs b/src/libstd/unstable/mutex.rs
index 8faedcbd9ed..c9d70915694 100644
--- a/src/libstd/unstable/mutex.rs
+++ b/src/libstd/unstable/mutex.rs
@@ -434,7 +434,7 @@ mod imp {
 
 #[cfg(windows)]
 mod imp {
-    use rt::global_heap::malloc_raw;
+    use rt::libc_heap::malloc_raw;
     use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR};
     use libc;
     use ptr;
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index da01da26709..aa10be1d1be 100644
--- a/src/libstd/vec.rs
+++ b/src/libstd/vec.rs
@@ -12,13 +12,12 @@
 
 use cast::{forget, transmute};
 use clone::Clone;
-use cmp::{Ord, Eq, Ordering, TotalEq, TotalOrd};
+use cmp::{Ord, Eq, Ordering, TotalEq, TotalOrd, max};
 use container::{Container, Mutable};
 use default::Default;
 use fmt;
 use iter::{DoubleEndedIterator, FromIterator, Extendable, Iterator, range};
-use libc::{free, c_void};
-use mem::{size_of, move_val_init};
+use mem::{min_align_of, move_val_init, size_of};
 use mem;
 use num;
 use num::{CheckedMul, CheckedAdd};
@@ -26,9 +25,9 @@ use ops::{Add, Drop};
 use option::{None, Option, Some, Expect};
 use ptr::RawPtr;
 use ptr;
-use rt::global_heap::{malloc_raw, realloc_raw};
 use raw::Slice;
 use RawVec = raw::Vec;
+use rt::heap::{allocate, reallocate, deallocate};
 use slice::{ImmutableEqVector, ImmutableVector, Items, MutItems, MutableVector};
 use slice::{MutableTotalOrdVector, OwnedVector, Vector};
 use slice::{MutableVectorAllocating};
@@ -92,11 +91,12 @@ impl<T> Vec<T> {
     /// let vec: Vec<int> = Vec::with_capacity(10);
     /// ```
     pub fn with_capacity(capacity: uint) -> Vec<T> {
+        if size_of::<T>() == 0 { return Vec { len: 0, cap: ::uint::MAX, ptr: 0 as *mut T } }
         if capacity == 0 {
             Vec::new()
         } else {
             let size = capacity.checked_mul(&size_of::<T>()).expect("capacity overflow");
-            let ptr = unsafe { malloc_raw(size) };
+            let ptr = unsafe { allocate(size, min_align_of::<T>()) };
             Vec { len: 0, cap: capacity, ptr: ptr as *mut T }
         }
     }
@@ -401,6 +401,23 @@ impl<T> Container for Vec<T> {
     }
 }
 
+// FIXME: #13996: need a way to mark the return value as `noalias`
+#[inline(never)]
+unsafe fn alloc_or_realloc<T>(ptr: *mut T, size: uint, old_size: uint) -> *mut T {
+    if old_size == 0 {
+        allocate(size, min_align_of::<T>()) as *mut T
+    } else {
+        reallocate(ptr as *mut u8, size, min_align_of::<T>(), old_size) as *mut T
+    }
+}
+
+#[inline]
+unsafe fn dealloc<T>(ptr: *mut T, len: uint) {
+    if size_of::<T>() != 0 {
+        deallocate(ptr as *mut u8, len * size_of::<T>(), min_align_of::<T>())
+    }
+}
+
 impl<T> Vec<T> {
     /// Returns the number of elements the vector can hold without
     /// reallocating.
@@ -477,33 +494,38 @@ impl<T> Vec<T> {
     /// assert_eq!(vec.capacity(), 11);
     /// ```
     pub fn reserve_exact(&mut self, capacity: uint) {
+        if size_of::<T>() == 0 { return }
         if capacity > self.cap {
             let size = capacity.checked_mul(&size_of::<T>()).expect("capacity overflow");
-            self.cap = capacity;
             unsafe {
-                self.ptr = realloc_raw(self.ptr as *mut u8, size) as *mut T;
+                self.ptr = alloc_or_realloc(self.ptr, size, self.cap * size_of::<T>());
             }
+            self.cap = capacity;
         }
     }
 
-    /// Shrink the capacity of the vector to match the length
+    /// Shrink the capacity of the vector as much as possible
     ///
     /// # Example
     ///
     /// ```rust
     /// let mut vec = vec!(1, 2, 3);
     /// vec.shrink_to_fit();
-    /// assert_eq!(vec.capacity(), vec.len());
     /// ```
     pub fn shrink_to_fit(&mut self) {
+        if size_of::<T>() == 0 { return }
         if self.len == 0 {
-            unsafe { free(self.ptr as *mut c_void) };
-            self.cap = 0;
-            self.ptr = 0 as *mut T;
+            if self.cap != 0 {
+                unsafe {
+                    dealloc(self.ptr, self.cap)
+                }
+                self.cap = 0;
+            }
         } else {
             unsafe {
                 // Overflow check is unnecessary as the vector is already at least this large.
-                self.ptr = realloc_raw(self.ptr as *mut u8, self.len * size_of::<T>()) as *mut T;
+                self.ptr = reallocate(self.ptr as *mut u8, self.len * size_of::<T>(),
+                                      min_align_of::<T>(), self.cap * size_of::<T>()) as *mut T;
             }
             self.cap = self.len;
         }
@@ -546,15 +568,20 @@ impl<T> Vec<T> {
     /// ```
     #[inline]
     pub fn push(&mut self, value: T) {
+        if size_of::<T>() == 0 {
+            // zero-size types consume no memory, so we can't rely on the address space running out
+            self.len = self.len.checked_add(&1).expect("length overflow");
+            unsafe { forget(value); }
+            return
+        }
         if self.len == self.cap {
-            if self.cap == 0 { self.cap += 2 }
             let old_size = self.cap * size_of::<T>();
-            self.cap = self.cap * 2;
-            let size = old_size * 2;
+            let size = max(old_size, 2 * size_of::<T>()) * 2;
             if old_size > size { fail!("capacity overflow") }
             unsafe {
-                self.ptr = realloc_raw(self.ptr as *mut u8, size) as *mut T;
+                self.ptr = alloc_or_realloc(self.ptr, size, self.cap * size_of::<T>());
             }
+            self.cap = max(self.cap, 2) * 2;
         }
 
         unsafe {
@@ -638,9 +665,10 @@ impl<T> Vec<T> {
     pub fn move_iter(self) -> MoveItems<T> {
         unsafe {
             let iter = transmute(self.as_slice().iter());
-            let ptr = self.ptr as *mut c_void;
+            let ptr = self.ptr;
+            let cap = self.cap;
             forget(self);
-            MoveItems { allocation: ptr, iter: iter }
+            MoveItems { allocation: ptr, cap: cap, iter: iter }
         }
     }
 
@@ -1386,11 +1414,13 @@ impl<T> Drop for Vec<T> {
     fn drop(&mut self) {
         // This is (and should always remain) a no-op if the fields are
         // zeroed (when moving out, because of #[unsafe_no_drop_flag]).
-        unsafe {
-            for x in self.as_mut_slice().iter() {
-                ptr::read(x);
+        if self.cap != 0 {
+            unsafe {
+                for x in self.as_mut_slice().iter() {
+                    ptr::read(x);
+                }
+                dealloc(self.ptr, self.cap)
             }
-            free(self.ptr as *mut c_void)
         }
     }
 }
@@ -1409,7 +1439,8 @@ impl<T:fmt::Show> fmt::Show for Vec<T> {
 
 /// An iterator that moves out of a vector.
 pub struct MoveItems<T> {
-    allocation: *mut c_void, // the block of memory allocated for the vector
+    allocation: *mut T, // the block of memory allocated for the vector
+    cap: uint, // the capacity of the vector
     iter: Items<'static, T>
 }
 
@@ -1440,9 +1471,11 @@ impl<T> DoubleEndedIterator<T> for MoveItems<T> {
 impl<T> Drop for MoveItems<T> {
     fn drop(&mut self) {
         // destroy the remaining elements
-        for _x in *self {}
-        unsafe {
-            free(self.allocation)
+        if self.cap != 0 {
+            for _x in *self {}
+            unsafe {
+                dealloc(self.allocation, self.cap);
+            }
         }
     }
 }
@@ -1493,7 +1526,7 @@ impl<T> FromVec<T> for ~[T] {
         let vp = v.as_mut_ptr();
 
         unsafe {
-            let ret = malloc_raw(size) as *mut RawVec<()>;
+            let ret = allocate(size, 8) as *mut RawVec<()>;
 
             (*ret).fill = len * mem::nonzero_size_of::<T>();
             (*ret).alloc = len * mem::nonzero_size_of::<T>();
diff --git a/src/libsync/arc.rs b/src/libsync/arc.rs
index f5369ec862f..226eb7afb5f 100644
--- a/src/libsync/arc.rs
+++ b/src/libsync/arc.rs
@@ -15,8 +15,9 @@
 
 use std::cast;
 use std::ptr;
-use std::rt::global_heap;
+use std::rt::heap::exchange_free;
 use std::sync::atomics;
+use std::mem::{min_align_of, size_of};
 
 /// An atomically reference counted wrapper for shared state.
 ///
@@ -190,7 +191,8 @@ impl<T: Share + Send> Drop for Arc<T> {
 
         if self.inner().weak.fetch_sub(1, atomics::Release) == 1 {
             atomics::fence(atomics::Acquire);
-            unsafe { global_heap::exchange_free(self.x as *u8) }
+            unsafe { exchange_free(self.x as *mut u8, size_of::<ArcInner<T>>(),
+                                   min_align_of::<ArcInner<T>>()) }
         }
     }
 }
@@ -240,7 +242,8 @@ impl<T: Share + Send> Drop for Weak<T> {
         // the memory orderings
         if self.inner().weak.fetch_sub(1, atomics::Release) == 1 {
             atomics::fence(atomics::Acquire);
-            unsafe { global_heap::exchange_free(self.x as *u8) }
+            unsafe { exchange_free(self.x as *mut u8, size_of::<ArcInner<T>>(),
+                                   min_align_of::<ArcInner<T>>()) }
         }
     }
 }