From ebbd90d28f148ec29004c340eeb05e0aa989f9a5 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Sat, 13 Jun 2015 15:13:16 -0400 Subject: [PATCH] Switch to direct HeapAlloc on Windows when not using jemalloc Signed-off-by: Peter Atashian --- src/liballoc/heap.rs | 119 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 102 insertions(+), 17 deletions(-) diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index e155dc86f325..1cc63588fddf 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -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); } } @@ -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::() 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::
() <= MIN_ALIGN); + } } #[cfg(test)]