Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to direct HeapAlloc on Windows when not using jemalloc #26265

Merged
merged 1 commit into from
Jun 15, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 102 additions & 17 deletions src/liballoc/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,47 +345,94 @@ mod imp {
not(jemalloc),
windows))]
mod imp {
use libc::{c_void, size_t};
use libc;
use core::mem::size_of;
use libc::{BOOL, DWORD, HANDLE, LPVOID, SIZE_T, INVALID_HANDLE_VALUE};
use libc::{WriteFile};
use super::MIN_ALIGN;

extern {
fn _aligned_malloc(size: size_t, align: size_t) -> *mut c_void;
fn _aligned_realloc(block: *mut c_void, size: size_t,
align: size_t) -> *mut c_void;
fn _aligned_free(ptr: *mut c_void);
extern "system" {
fn GetProcessHeap() -> HANDLE;
fn GetStdHandle(nStdHandle: DWORD) -> HANDLE;
fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) -> BOOL;
}

#[repr(C)] #[allow(non_snake_case)]
struct HEAP_SUMMARY {
cb: DWORD,
cbAllocated: SIZE_T,
cbCommitted: SIZE_T,
cbReserved: SIZE_T,
cbMaxReserve: SIZE_T,
}
#[allow(non_camel_case_types)]
type LPHEAP_SUMMARY = *mut HEAP_SUMMARY;

#[repr(C)]
struct Header(*mut u8);

const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010;
const STD_OUTPUT_HANDLE: DWORD = -11i32 as u32;

#[inline]
unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
&mut *(ptr as *mut Header).offset(-1)
}

#[inline]
unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
*get_header(aligned) = Header(ptr);
aligned
}

#[inline]
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
libc::malloc(size as size_t) as *mut u8
HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
} else {
_aligned_malloc(size as size_t, align as size_t) as *mut u8
let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8;
if ptr.is_null() { return ptr }
align_ptr(ptr, align)
}
}

#[inline]
pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
libc::realloc(ptr as *mut c_void, size as size_t) as *mut u8
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
} else {
_aligned_realloc(ptr as *mut c_void, size as size_t, align as size_t) as *mut u8
let header = get_header(ptr);
let new = HeapReAlloc(GetProcessHeap(), 0, header.0 as LPVOID,
(size + align) as SIZE_T) as *mut u8;
if new.is_null() { return new }
align_ptr(new, align)
}
}

#[inline]
pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize,
_align: usize) -> usize {
old_size
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> usize {
if align <= MIN_ALIGN {
let new = HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, ptr as LPVOID,
size as SIZE_T) as *mut u8;
if new.is_null() { old_size } else { size }
} else {
old_size
}
}

#[inline]
pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
if align <= MIN_ALIGN {
libc::free(ptr as *mut libc::c_void)
let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
debug_assert!(err != 0);
} else {
_aligned_free(ptr as *mut c_void)
let header = get_header(ptr);
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
debug_assert!(err != 0);
}
}

Expand All @@ -394,7 +441,45 @@ mod imp {
size
}

pub fn stats_print() {}
pub fn stats_print() {
use core::fmt::{Error, Result, Write};
use core::ptr::null_mut;
use core::raw::Repr;
use core::result::Result::{Ok, Err};
struct Console(HANDLE);
impl Write for Console {
fn write_str(&mut self, s: &str) -> Result {
let repr = s.repr();
let mut written = 0;
let err = unsafe { WriteFile(self.0, repr.data as LPVOID, repr.len as DWORD,
&mut written, null_mut()) };
if written as usize != repr.len { return Err(Error) }
if err == 0 { return Err(Error) }
Ok(())
}
}
let mut hs = HEAP_SUMMARY {
cb: size_of::<HEAP_SUMMARY>() as DWORD,
cbAllocated: 0,
cbCommitted: 0,
cbReserved: 0,
cbMaxReserve: 0,
};
let err = unsafe { HeapSummary(GetProcessHeap(), 0, &mut hs) };
assert!(err != 0);
let handle = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) };
if handle.is_null() || handle == INVALID_HANDLE_VALUE { panic!("Failed to open stdout") }
let mut out = Console(handle);
writeln!(&mut out, "Allocated: {}", hs.cbAllocated).unwrap();
writeln!(&mut out, "Committed: {}", hs.cbCommitted).unwrap();
writeln!(&mut out, "Reserved: {}", hs.cbReserved).unwrap();
writeln!(&mut out, "MaxReserve: {}", hs.cbMaxReserve).unwrap();
}

#[test]
fn alignment_header_size() {
assert!(size_of::<Header>() <= MIN_ALIGN);
}
}

#[cfg(test)]
Expand Down