servo/components/allocator/lib.rs
2018-05-18 11:44:47 -05:00

141 lines
4.7 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Selecting the default global allocator for Servo
#![cfg_attr(feature = "unstable", feature(global_allocator, allocator_api, alloc_system))]
#[cfg(feature = "unstable")]
#[global_allocator]
static ALLOC: Allocator = Allocator;
pub use platform::*;
#[cfg(all(feature = "unstable", not(windows)))]
mod platform {
extern crate jemalloc_sys as ffi;
use std::alloc::{GlobalAlloc, Layout, Opaque, System};
use std::os::raw::{c_int, c_void};
/// Get the size of a heap block.
pub unsafe extern "C" fn usable_size(ptr: *const c_void) -> usize {
ffi::malloc_usable_size(ptr as *const _)
}
/// Memory allocation APIs compatible with libc
pub mod libc_compat {
pub use super::ffi::{malloc, realloc, free};
}
pub struct Allocator;
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values.
#[cfg(all(any(target_arch = "arm",
target_arch = "mips",
target_arch = "mipsel",
target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "powerpc64",
target_arch = "powerpc64le",
target_arch = "mips64",
target_arch = "s390x",
target_arch = "sparc64")))]
const MIN_ALIGN: usize = 16;
fn layout_to_flags(align: usize, size: usize) -> c_int {
// If our alignment is less than the minimum alignment they we may not
// have to pass special flags asking for a higher alignment. If the
// alignment is greater than the size, however, then this hits a sort of odd
// case where we still need to ask for a custom alignment. See #25 for more
// info.
if align <= MIN_ALIGN && align <= size {
0
} else {
// Equivalent to the MALLOCX_ALIGN(a) macro.
align.trailing_zeros() as _
}
}
unsafe impl GlobalAlloc for Allocator {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
let flags = layout_to_flags(layout.align(), layout.size());
ffi::mallocx(layout.size(), flags) as *mut Opaque
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
ffi::calloc(1, layout.size()) as *mut Opaque
} else {
let flags = layout_to_flags(layout.align(), layout.size()) | ffi::MALLOCX_ZERO;
ffi::mallocx(layout.size(), flags) as *mut Opaque
}
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
let flags = layout_to_flags(layout.align(), layout.size());
ffi::sdallocx(ptr as *mut _, layout.size(), flags)
}
#[inline]
unsafe fn realloc(&self,
ptr: *mut Opaque,
layout: Layout,
new_size: usize) -> *mut Opaque {
let flags = layout_to_flags(layout.align(), new_size);
ffi::rallocx(ptr as *mut _, new_size, flags) as *mut Opaque
}
#[inline]
fn oom(&self) -> ! {
System.oom()
}
}
}
#[cfg(all(feature = "unstable", windows))]
mod platform {
extern crate alloc_system;
extern crate kernel32;
pub use self::alloc_system::System as Allocator;
use self::kernel32::{GetProcessHeap, HeapSize, HeapValidate};
use std::os::raw::c_void;
/// Get the size of a heap block.
pub unsafe extern "C" fn usable_size(mut ptr: *const c_void) -> usize {
let heap = GetProcessHeap();
if HeapValidate(heap, 0, ptr) == 0 {
ptr = *(ptr as *const *const c_void).offset(-1);
}
HeapSize(heap, 0, ptr) as usize
}
}
#[cfg(not(feature = "unstable"))]
mod platform {
use std::os::raw::c_void;
/// Without `#[global_allocator]` we cannot be certain of what allocator is used
/// or how it is linked. We therefore disable memory reporting. (Return zero.)
pub unsafe extern "C" fn usable_size(_ptr: *const c_void) -> usize {
0
}
/// Memory allocation APIs compatible with libc
pub mod libc_compat {
extern crate libc;
pub use self::libc::{malloc, realloc, free};
}
}