Skip to content

add back jemalloc to the tree #13742

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

Closed
wants to merge 2 commits into from
Closed
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -12,3 +12,6 @@
[submodule "src/compiler-rt"]
path = src/compiler-rt
url = https://github.com/rust-lang/compiler-rt.git
[submodule "src/jemalloc"]
path = src/jemalloc
url = https://github.com/jemalloc/jemalloc.git
1 change: 1 addition & 0 deletions configure
Original file line number Diff line number Diff line change
@@ -762,6 +762,7 @@ do
for s in 0 1 2 3
do
make_dir $t/rt/stage$s
make_dir $t/rt/jemalloc
make_dir $t/rt/libuv
make_dir $t/rt/libuv/src/ares
make_dir $t/rt/libuv/src/eio
2 changes: 1 addition & 1 deletion mk/crates.mk
Original file line number Diff line number Diff line change
@@ -56,7 +56,7 @@ HOST_CRATES := syntax rustc rustdoc fourcc hexfloat
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
TOOLS := compiletest rustdoc rustc

DEPS_std := libc native:rustrt native:compiler-rt native:backtrace
DEPS_std := libc native:rustrt native:compiler-rt native:backtrace native:jemalloc
DEPS_green := std rand native:context_switch
DEPS_rustuv := std native:uv native:uv_support
DEPS_native := std
48 changes: 44 additions & 4 deletions mk/rt.mk
Original file line number Diff line number Diff line change
@@ -121,10 +121,13 @@ $(foreach lib,$(NATIVE_LIBS), \
################################################################################
# Building third-party targets with external build systems
#
# The only current member of this section is libuv, but long ago this used to
# also be occupied by jemalloc. This location is meant for dependencies which
# have external build systems. It is still assumed that the output of each of
# these steps is a static library in the correct location.
# This location is meant for dependencies which have external build systems. It
# is still assumed that the output of each of these steps is a static library
# in the correct location.
################################################################################

################################################################################
# libuv
################################################################################

define DEF_LIBUV_ARCH_VAR
@@ -160,6 +163,7 @@ else ifeq ($(OSTYPE_$(1)), unknown-freebsd)
else ifeq ($(OSTYPE_$(1)), linux-androideabi)
LIBUV_OSTYPE_$(1) := android
LIBUV_ARGS_$(1) := PLATFORM=android host=android OS=linux
JEMALLOC_ARGS_$(1) := --disable-tls
else
LIBUV_OSTYPE_$(1) := linux
endif
@@ -219,6 +223,42 @@ $$(LIBUV_DIR_$(1))/Release/libuv.a: $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)) \

endif

################################################################################
# jemalloc
################################################################################

ifdef CFG_ENABLE_FAST_MAKE
JEMALLOC_DEPS := $(S)/.gitmodules
else
JEMALLOC_DEPS := $(wildcard \
$(S)src/jemalloc/* \
$(S)src/jemalloc/*/* \
$(S)src/jemalloc/*/*/* \
$(S)src/jemalloc/*/*/*/*)
endif

JEMALLOC_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),jemalloc)
ifeq ($$(CFG_WINDOWSY_$(1)),1)
JEMALLOC_REAL_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),jemalloc)
else
JEMALLOC_REAL_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),jemalloc_pic)
endif
JEMALLOC_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(JEMALLOC_NAME_$(1))
JEMALLOC_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/jemalloc

$$(JEMALLOC_LIB_$(1)): $$(JEMALLOC_DEPS) $$(MKFILE_DEPS)
@$$(call E, make: jemalloc)
cd "$(S)src/jemalloc"; autoconf
cd "$$(JEMALLOC_BUILD_DIR_$(1))"; "$(S)src/jemalloc/configure" \
$$(JEMALLOC_ARGS_$(1)) --with-jemalloc-prefix=je --enable-autogen \
--disable-experimental --build=$(CFG_BUILD_TRIPLE) --host=$(1) \
CC="$$(CC_$(1))" \
AR="$$(AR_$(1))" \
RANLIB="$$(AR_$(1)) s" \
EXTRA_CFLAGS="$$(CFG_GCCISH_CFLAGS)"
$$(Q)$$(MAKE) -C "$$(JEMALLOC_BUILD_DIR_$(1))" build_lib_static
$$(Q)cp $$(JEMALLOC_BUILD_DIR_$(1))/lib/$$(JEMALLOC_REAL_NAME_$(1)) $$(JEMALLOC_LIB_$(1))

################################################################################
# compiler-rt
################################################################################
4 changes: 3 additions & 1 deletion mk/tests.mk
Original file line number Diff line number Diff line change
@@ -240,6 +240,7 @@ ALL_HS := $(filter-out $(S)src/rt/vg/valgrind.h \
tidy:
@$(call E, check: formatting)
$(Q)find $(S)src -name '*.r[sc]' \
| grep '^$(S)src/jemalloc' -v \
| grep '^$(S)src/libuv' -v \
| grep '^$(S)src/llvm' -v \
| grep '^$(S)src/gyp' -v \
@@ -264,8 +265,9 @@ tidy:
$(Q)find $(S)src -type f -perm +111 \
-not -name '*.rs' -and -not -name '*.py' \
-and -not -name '*.sh' \
| grep '^$(S)src/llvm' -v \
| grep '^$(S)src/jemalloc' -v \
| grep '^$(S)src/libuv' -v \
| grep '^$(S)src/llvm' -v \
| grep '^$(S)src/gyp' -v \
| grep '^$(S)src/etc' -v \
| grep '^$(S)src/doc' -v \
1 change: 1 addition & 0 deletions src/jemalloc
Submodule jemalloc added at 46c0af
30 changes: 26 additions & 4 deletions src/libarena/lib.rs
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ use std::cast::{transmute, transmute_mut, transmute_mut_lifetime};
use std::cast;
use std::cell::{Cell, RefCell};
use std::mem;
use std::mem::min_align_of;
use std::ptr::read;
use std::cmp;
use std::num;
@@ -204,7 +205,7 @@ impl Arena {
#[inline]
fn alloc_copy<'a, T>(&'a mut self, op: || -> T) -> &'a T {
unsafe {
let ptr = self.alloc_copy_inner(mem::size_of::<T>(), mem::min_align_of::<T>());
let ptr = self.alloc_copy_inner(mem::size_of::<T>(), min_align_of::<T>());
let ptr: *mut T = transmute(ptr);
mem::move_val_init(&mut (*ptr), op());
return transmute(ptr);
@@ -261,7 +262,7 @@ impl Arena {
unsafe {
let tydesc = get_tydesc::<T>();
let (ty_ptr, ptr) =
self.alloc_noncopy_inner(mem::size_of::<T>(), mem::min_align_of::<T>());
self.alloc_noncopy_inner(mem::size_of::<T>(), min_align_of::<T>());
let ty_ptr: *mut uint = transmute(ty_ptr);
let ptr: *mut T = transmute(ptr);
// Write in our tydesc along with a bit indicating that it
@@ -354,9 +355,10 @@ struct TypedArenaChunk<T> {

impl<T> TypedArenaChunk<T> {
#[inline]
#[cfg(stage0)]
fn new(next: Option<~TypedArenaChunk<T>>, capacity: uint) -> ~TypedArenaChunk<T> {
let mut size = mem::size_of::<TypedArenaChunk<T>>();
size = round_up(size, mem::min_align_of::<T>());
size = round_up(size, min_align_of::<T>());
let elem_size = mem::size_of::<T>();
let elems_size = elem_size.checked_mul(&capacity).unwrap();
size = size.checked_add(&elems_size).unwrap();
@@ -372,6 +374,26 @@ impl<T> TypedArenaChunk<T> {
chunk
}

#[inline]
#[cfg(not(stage0))]
fn new(next: Option<~TypedArenaChunk<T>>, capacity: uint) -> ~TypedArenaChunk<T> {
let mut size = mem::size_of::<TypedArenaChunk<T>>();
size = round_up(size, mem::min_align_of::<T>());
let elem_size = mem::size_of::<T>();
let elems_size = elem_size.checked_mul(&capacity).unwrap();
size = size.checked_add(&elems_size).unwrap();

let mut chunk = unsafe {
let chunk = global_heap::exchange_malloc(size, min_align_of::<TypedArenaChunk<T>>());
let mut chunk: ~TypedArenaChunk<T> = cast::transmute(chunk);
mem::move_val_init(&mut chunk.next, next);
chunk
};

chunk.capacity = capacity;
chunk
}

/// Destroys this arena chunk. If the type descriptor is supplied, the
/// drop glue is called; otherwise, drop glue is not called.
#[inline]
@@ -401,7 +423,7 @@ impl<T> TypedArenaChunk<T> {
fn start(&self) -> *u8 {
let this: *TypedArenaChunk<T> = self;
unsafe {
cast::transmute(round_up(this.offset(1) as uint, mem::min_align_of::<T>()))
cast::transmute(round_up(this.offset(1) as uint, min_align_of::<T>()))
}
}

5 changes: 3 additions & 2 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
@@ -352,15 +352,16 @@ fn require_alloc_fn(bcx: &Block, info_ty: ty::t, it: LangItem) -> ast::DefId {

pub fn malloc_raw_dyn<'a>(bcx: &'a Block<'a>,
ptr_ty: ty::t,
size: ValueRef)
size: ValueRef,
align: ValueRef)
-> Result<'a> {
let _icx = push_ctxt("malloc_raw_exchange");
let ccx = bcx.ccx();

// Allocate space:
let r = callee::trans_lang_call(bcx,
require_alloc_fn(bcx, ptr_ty, ExchangeMallocFnLangItem),
[size],
[size, align],
None);

let llty_ptr = type_of::type_of(ccx, ptr_ty);
5 changes: 3 additions & 2 deletions src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ use middle::typeck::MethodCall;
use util::common::indenter;
use util::ppaux::Repr;
use util::nodemap::NodeMap;
use middle::trans::machine::{llsize_of, llsize_of_alloc};
use middle::trans::machine::{llalign_of_min, llsize_of, llsize_of_alloc};
use middle::trans::type_::Type;

use syntax::ast;
@@ -1170,10 +1170,11 @@ fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
let fcx = bcx.fcx;
let llty = type_of::type_of(bcx.ccx(), contents_ty);
let size = llsize_of(bcx.ccx(), llty);
let align = C_uint(bcx.ccx(), llalign_of_min(bcx.ccx(), llty) as uint);
// We need to a make a pointer type because box_ty is ty_bot
// if content_ty is, e.g. ~fail!().
let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty);
let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size);
let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size, align);
// Unique boxes do not allocate for zero-size types. The standard library may assume
// that `free` is never called on the pointer returned for `~ZeroSizeType`.
let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
4 changes: 3 additions & 1 deletion src/librustc/middle/trans/tvec.rs
Original file line number Diff line number Diff line change
@@ -278,7 +278,9 @@ pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>,

let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));

let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize);
// ~[T] is not going to be changed to support alignment, since it's obsolete.
let align = C_uint(ccx, 8);
let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize, align);
Store(bcx, fill, GEPi(bcx, val, [0u, abi::vec_elt_fill]));
Store(bcx, alloc, GEPi(bcx, val, [0u, abi::vec_elt_alloc]));

19 changes: 18 additions & 1 deletion src/libstd/rt/global_heap.rs
Original file line number Diff line number Diff line change
@@ -65,7 +65,7 @@ pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 {
}

/// The allocator for unique pointers without contained managed pointers.
#[cfg(not(test))]
#[cfg(not(test), stage0)]
#[lang="exchange_malloc"]
#[inline]
pub unsafe fn exchange_malloc(size: uint) -> *mut u8 {
@@ -81,6 +81,23 @@ pub unsafe fn exchange_malloc(size: uint) -> *mut u8 {
}
}

/// The allocator for unique pointers without contained managed pointers.
#[cfg(not(test), not(stage0))]
#[lang="exchange_malloc"]
#[inline]
pub unsafe fn exchange_malloc(size: uint, _align: uint) -> *mut u8 {
// 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.
static EMPTY: () = ();

if size == 0 {
&EMPTY as *() as *mut u8
} else {
malloc_raw(size)
}
}

// FIXME: #7496
#[cfg(not(test))]
#[lang="closure_exchange_malloc"]
93 changes: 93 additions & 0 deletions src/libstd/rt/heap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// 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.

use intrinsics::{abort, cttz32};
use libc::{c_int, c_void, size_t};
use ptr::RawPtr;

#[link(name = "jemalloc", kind = "static")]
#[link(name = "pthread")]
extern {
fn jemallocx(size: size_t, flags: c_int) -> *mut c_void;
fn jerallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
fn jexallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
fn jedallocx(ptr: *mut c_void, flags: c_int);
fn jenallocx(size: size_t, flags: c_int) -> size_t;
}

// 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 = jemallocx(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 = jerallocx(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 {
jexallocx(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) {
jedallocx(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 { jenallocx(size as size_t, mallocx_align(align)) as uint }
}
3 changes: 3 additions & 0 deletions src/libstd/rt/mod.rs
Original file line number Diff line number Diff line change
@@ -88,6 +88,9 @@ mod macros;
/// The global (exchange) heap.
pub mod global_heap;

/// The low-level memory allocation API.
pub mod heap;

/// Implementations of language-critical runtime features like @.
pub mod task;