diff options
| author | bors <bors@rust-lang.org> | 2013-06-30 15:02:05 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-06-30 15:02:05 -0700 |
| commit | 040ac2a93270b4420c59621521d554a078e2d451 (patch) | |
| tree | 16dc8d87d4352a8e695949c906af4e5e55f2f47d /src/libstd | |
| parent | ca835f482cebcd353db789e45f9cec72db1a24ed (diff) | |
| parent | 4a29d6eb3f20c2b7a05bb9c9c2f964da606e39ca (diff) | |
| download | rust-040ac2a93270b4420c59621521d554a078e2d451.tar.gz rust-040ac2a93270b4420c59621521d554a078e2d451.zip | |
auto merge of #7495 : thestinger/rust/exchange, r=cmr
With these changes, exchange allocator headers are never initialized, read or written to. Removing the header will now just involve updating the code in trans using an offset to only do it if the type contained is managed. The only thing blocking removing the initialization of the last field in the header was ~fn since it uses it to store the dynamic size/types due to captures. I temporarily switched it to a `closure_exchange_alloc` lang item (it uses the same `exchange_free`) and #7496 is filed about removing that. Since the `exchange_free` call is now inlined all over the codebase, I don't think we should have an assert for null. It doesn't currently ever happen, but it would be fine if we started generating code that did do it. The `exchange_free` function also had a comment declaring that it must not fail, but a regular assert would cause a failure. I also removed the atomic counter because valgrind can already find these leaks, and we have valgrind bots now. Note that exchange free does not currently print an error an out-of-memory when it aborts, because our `io` code may allocate. We could probably get away with a `#[rust_stack]` call to a `stdio` function but it would be better to make a write system call.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/managed.rs | 1 | ||||
| -rw-r--r-- | src/libstd/os.rs | 6 | ||||
| -rw-r--r-- | src/libstd/rt/global_heap.rs | 128 | ||||
| -rw-r--r-- | src/libstd/unstable/exchange_alloc.rs | 83 | ||||
| -rw-r--r-- | src/libstd/unstable/intrinsics.rs | 4 | ||||
| -rw-r--r-- | src/libstd/unstable/lang.rs | 17 | ||||
| -rw-r--r-- | src/libstd/vec.rs | 30 |
7 files changed, 111 insertions, 158 deletions
diff --git a/src/libstd/managed.rs b/src/libstd/managed.rs index b71b3b503c2..2c9fcb2999f 100644 --- a/src/libstd/managed.rs +++ b/src/libstd/managed.rs @@ -17,7 +17,6 @@ use ptr::to_unsafe_ptr; pub mod raw { use std::unstable::intrinsics::TyDesc; - pub static RC_EXCHANGE_UNIQUE : uint = (-1) as uint; pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; pub static RC_IMMORTAL : uint = 0x77777777; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 1fbcda12dce..9b74754d711 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -730,7 +730,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { #[cfg(windows)] unsafe fn get_list(p: &Path) -> ~[~str] { use libc::consts::os::extra::INVALID_HANDLE_VALUE; - use libc::wcslen; + use libc::{wcslen, free}; use libc::funcs::extra::kernel32::{ FindFirstFileW, FindNextFileW, @@ -739,7 +739,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { use os::win32::{ as_utf16_p }; - use rt::global_heap::{malloc_raw, free_raw}; + use rt::global_heap::malloc_raw; #[nolink] extern { unsafe fn rust_list_dir_wfd_size() -> libc::size_t; @@ -772,7 +772,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { ::cast::transmute(wfd_ptr)); } FindClose(find_handle); - free_raw(wfd_ptr); + free(wfd_ptr) } strings } diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 1e9f9aab834..f669dc753d6 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -8,62 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use sys::{size_of}; -use libc::{c_void, size_t, uintptr_t}; -use c_malloc = libc::malloc; -use c_free = libc::free; +use libc::{c_char, c_void, size_t, uintptr_t, free, malloc}; use managed::raw::{BoxHeaderRepr, BoxRepr}; -use cast::transmute; -use unstable::intrinsics::{atomic_xadd,atomic_xsub,TyDesc}; -use ptr::null; +use unstable::intrinsics::TyDesc; +use sys::size_of; -pub unsafe fn malloc(td: *TyDesc, size: uint) -> *c_void { - assert!(td.is_not_null()); - - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert!(p.is_not_null()); - - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); - - let exchange_count = &mut *exchange_count_ptr(); - atomic_xadd(exchange_count, 1); - - return transmute(box); -} -/** -Thin wrapper around libc::malloc, none of the box header -stuff in exchange_alloc::malloc -*/ -pub unsafe fn malloc_raw(size: uint) -> *c_void { - let p = c_malloc(size as size_t); - if p.is_null() { - fail!("Failure in malloc_raw: result ptr is null"); - } - p -} - -pub unsafe fn free(ptr: *c_void) { - let exchange_count = &mut *exchange_count_ptr(); - atomic_xsub(exchange_count, 1); - - assert!(ptr.is_not_null()); - c_free(ptr); -} -///Thin wrapper around libc::free, as with exchange_alloc::malloc_raw -pub unsafe fn free_raw(ptr: *c_void) { - c_free(ptr); +extern { + #[rust_stack] + fn abort(); } fn get_box_size(body_size: uint, body_align: uint) -> uint { let header_size = size_of::<BoxHeaderRepr>(); // FIXME (#2699): This alignment calculation is suspicious. Is it right? let total_size = align_to(header_size, body_align) + body_size; - return total_size; + total_size } // Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power @@ -73,11 +32,74 @@ fn align_to(size: uint, align: uint) -> uint { (size + align - 1) & !(align - 1) } -fn exchange_count_ptr() -> *mut int { - // XXX: Need mutable globals - unsafe { transmute(&rust_exchange_count) } +/// A wrapper around libc::malloc, aborting on out-of-memory +pub unsafe fn malloc_raw(size: uint) -> *c_void { + let p = malloc(size as size_t); + if p.is_null() { + // we need a non-allocating way to print an error here + abort(); + } + p } -extern { - static rust_exchange_count: uintptr_t; +// FIXME #4942: Make these signatures agree with exchange_alloc's signatures +#[cfg(stage0, not(test))] +#[lang="exchange_malloc"] +#[inline] +pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + let p = malloc_raw(total_size as uint); + + let box: *mut BoxRepr = p as *mut BoxRepr; + (*box).header.ref_count = -1; + (*box).header.type_desc = td; + + box as *c_char +} + +// FIXME #4942: Make these signatures agree with exchange_alloc's signatures +#[cfg(not(stage0), not(test))] +#[lang="exchange_malloc"] +#[inline] +pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + malloc_raw(total_size as uint) as *c_char +} + +// FIXME: #7496 +#[cfg(not(test))] +#[lang="closure_exchange_malloc"] +#[inline] +pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + let p = malloc_raw(total_size as uint); + + let box: *mut BoxRepr = p as *mut BoxRepr; + (*box).header.type_desc = td; + + box as *c_char +} + +// 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: *c_char) { + free(ptr as *c_void); } diff --git a/src/libstd/unstable/exchange_alloc.rs b/src/libstd/unstable/exchange_alloc.rs deleted file mode 100644 index 5c47901df48..00000000000 --- a/src/libstd/unstable/exchange_alloc.rs +++ /dev/null @@ -1,83 +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. - -use sys::size_of; -use libc::{c_void, size_t}; -use c_malloc = libc::malloc; -use c_free = libc::free; -use managed::raw::{BoxHeaderRepr, BoxRepr}; -use cast::transmute; -use unstable::intrinsics::{atomic_xadd,atomic_xsub}; -use ptr::null; -#[cfg(stage0)] -use intrinsic::TyDesc; -#[cfg(not(stage0))] -use unstable::intrinsics::TyDesc; - -pub unsafe fn malloc(td: *TyDesc, size: uint) -> *c_void { - assert!(td.is_not_null()); - - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert!(p.is_not_null()); - - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); - - let exchange_count = &mut *rust_get_exchange_count_ptr(); - atomic_xadd(exchange_count, 1); - - return transmute(box); -} -/** -Thin wrapper around libc::malloc, none of the box header -stuff in exchange_alloc::malloc -*/ -pub unsafe fn malloc_raw(size: uint) -> *c_void { - let p = c_malloc(size as size_t); - if p.is_null() { - fail!("Failure in malloc_raw: result ptr is null"); - } - p -} - -pub unsafe fn free(ptr: *c_void) { - let exchange_count = &mut *rust_get_exchange_count_ptr(); - atomic_xsub(exchange_count, 1); - - assert!(ptr.is_not_null()); - c_free(ptr); -} -///Thin wrapper around libc::free, as with exchange_alloc::malloc_raw -pub unsafe fn free_raw(ptr: *c_void) { - c_free(ptr); -} - -fn get_box_size(body_size: uint, body_align: uint) -> uint { - let header_size = size_of::<BoxHeaderRepr>(); - // FIXME (#2699): This alignment calculation is suspicious. Is it right? - let total_size = align_to(header_size, body_align) + body_size; - return total_size; -} - -// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power -// of two. -fn align_to(size: uint, align: uint) -> uint { - assert!(align != 0); - (size + align - 1) & !(align - 1) -} - -extern { - #[rust_stack] - fn rust_get_exchange_count_ptr() -> *mut int; -} diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 1254a591293..500143fb577 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -308,6 +308,10 @@ pub extern "rust-intrinsic" { /// Returns `true` if a type requires drop glue. pub fn needs_drop<T>() -> bool; + /// Returns `true` if a type is managed (will be allocated on the local heap) + #[cfg(not(stage0))] + pub fn contains_managed<T>() -> bool; + #[cfg(not(stage0))] pub fn visit_tydesc(td: *TyDesc, tv: @TyVisitor); diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index d37579b0c47..fddd847af34 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -22,7 +22,6 @@ use rt::task::Task; use rt::local::Local; use option::{Option, Some, None}; use io; -use rt::global_heap; #[allow(non_camel_case_types)] pub type rust_task = c_void; @@ -150,13 +149,6 @@ unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { } } -// FIXME #4942: Make these signatures agree with exchange_alloc's signatures -#[lang="exchange_malloc"] -#[inline] -pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { - transmute(global_heap::malloc(transmute(td), transmute(size))) -} - /// Because this code is so perf. sensitive, use a static constant so that /// debug printouts are compiled out most of the time. static ENABLE_DEBUG: bool = false; @@ -228,15 +220,6 @@ impl DebugPrints for io::fd_t { } } -// 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. -#[lang="exchange_free"] -#[inline] -pub unsafe fn exchange_free(ptr: *c_char) { - global_heap::free(transmute(ptr)) -} - #[lang="malloc"] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { match context() { diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index cff4ac10145..272ad0ac705 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -35,7 +35,7 @@ use unstable::intrinsics; #[cfg(stage0)] use intrinsic::{get_tydesc}; #[cfg(not(stage0))] -use unstable::intrinsics::{get_tydesc}; +use unstable::intrinsics::{get_tydesc, contains_managed}; use vec; use util; @@ -1517,6 +1517,7 @@ impl<T> OwnedVector<T> for ~[T] { * * n - The number of elements to reserve space for */ #[inline] + #[cfg(stage0)] fn reserve(&mut self, n: uint) { // Only make the (slow) call into the runtime if we have to use managed; @@ -1535,6 +1536,33 @@ impl<T> OwnedVector<T> for ~[T] { } /** + * Reserves capacity for exactly `n` elements in the given vector. + * + * If the capacity for `self` is already equal to or greater than the requested + * capacity, then no action is taken. + * + * # Arguments + * + * * n - The number of elements to reserve space for + */ + #[inline] + #[cfg(not(stage0))] + fn reserve(&mut self, n: uint) { + // Only make the (slow) call into the runtime if we have to + if self.capacity() < n { + unsafe { + let ptr: **raw::VecRepr = cast::transmute(self); + let td = get_tydesc::<T>(); + if contains_managed::<T>() { + rustrt::vec_reserve_shared_actual(td, ptr, n as libc::size_t); + } else { + rustrt::vec_reserve_shared(td, ptr, n as libc::size_t); + } + } + } + } + + /** * Reserves capacity for at least `n` elements in the given vector. * * This function will over-allocate in order to amortize the allocation costs |
