heap.rs 6.6 KB
Newer Older
D
Daniel Micay 已提交
1 2 3 4 5 6 7 8 9 10
// 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.

D
Daniel Micay 已提交
11
// FIXME: #13994: port to the sized deallocation API when available
12
// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias` and `nonnull`
D
Daniel Micay 已提交
13

14 15 16
use core::intrinsics::{abort, cttz32};
use core::option::{None, Option};
use core::ptr::{RawPtr, mut_null, null};
17
use libc::{c_char, c_int, c_void, size_t};
18 19 20

#[cfg(not(test))] use core::raw;
#[cfg(not(test))] use util;
D
Daniel Micay 已提交
21 22 23 24 25 26 27 28

#[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;
29 30 31
    fn je_malloc_stats_print(write_cb: Option<extern "C" fn(cbopaque: *mut c_void, *c_char)>,
                             cbopaque: *mut c_void,
                             opts: *c_char);
D
Daniel Micay 已提交
32 33 34
}

// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
D
Daniel Micay 已提交
35
#[cfg(not(windows), not(target_os = "android"))]
D
Daniel Micay 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
#[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 }
}
108

109 110 111 112 113 114 115 116 117 118
/// Print implementation-defined allocator statistics.
///
/// These statistics may be inconsistent if other threads use the allocator during the call.
#[unstable]
pub fn stats_print() {
    unsafe {
        je_malloc_stats_print(None, mut_null(), null())
    }
}

119 120 121 122 123
// 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.
pub static mut EMPTY: uint = 12345;

124
/// The allocator for unique pointers.
D
Daniel Micay 已提交
125
#[cfg(not(test))]
126 127
#[lang="exchange_malloc"]
#[inline]
128
unsafe fn exchange_malloc(size: uint, align: uint) -> *mut u8 {
129
    if size == 0 {
130
        &EMPTY as *uint as *mut u8
131 132 133 134 135
    } else {
        allocate(size, align)
    }
}

136
#[cfg(not(test), stage0)]
137 138
#[lang="exchange_free"]
#[inline]
139 140
unsafe fn exchange_free(ptr: *mut u8) {
    deallocate(ptr, 0, 8);
141 142
}

143 144 145 146 147 148 149
#[cfg(not(test), not(stage0))]
#[lang="exchange_free"]
#[inline]
unsafe fn exchange_free(ptr: *mut u8, size: uint, align: uint) {
    deallocate(ptr, size, align);
}

150 151 152 153
// FIXME: #7496
#[cfg(not(test))]
#[lang="closure_exchange_malloc"]
#[inline]
154
#[allow(deprecated)]
155
unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *mut u8 {
156
    let total_size = util::get_box_size(size, align);
157 158
    let p = allocate(total_size, 8);

159
    let alloc = p as *mut raw::Box<()>;
160 161 162 163 164 165 166 167 168
    (*alloc).drop_glue = drop_glue;

    alloc as *mut u8
}

// hack for libcore
#[no_mangle]
#[doc(hidden)]
#[deprecated]
D
Daniel Micay 已提交
169
#[cfg(not(test))]
170 171
pub unsafe extern "C" fn rust_allocate(size: uint, align: uint) -> *mut u8 {
    allocate(size, align)
172 173 174 175 176 177 178
}

// hack for libcore
#[no_mangle]
#[doc(hidden)]
#[deprecated]
#[cfg(not(test))]
179
pub unsafe extern "C" fn rust_deallocate(ptr: *mut u8, size: uint, align: uint) {
180
    deallocate(ptr, size, align)
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
}

#[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]
        })
    }
}