diff --git a/.gitmodules b/.gitmodules index f9da507b72a..37dbb30c82a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,3 +15,6 @@ [submodule "src/rt/hoedown"] path = src/rt/hoedown url = https://github.com/rust-lang/hoedown.git +[submodule "src/jemalloc"] + path = src/jemalloc + url = https://github.com/rust-lang/jemalloc.git diff --git a/configure b/configure index d189c8cb6cd..3ab71f762f2 100755 --- a/configure +++ b/configure @@ -782,6 +782,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 diff --git a/mk/crates.mk b/mk/crates.mk index b75b5ba81e2..0437e08de28 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -57,7 +57,7 @@ CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc DEPS_core := -DEPS_std := core libc native:rustrt native:compiler-rt native:backtrace +DEPS_std := core 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 diff --git a/mk/rt.mk b/mk/rt.mk index df47f4a12d9..e4a548dd7bf 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -122,10 +122,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 @@ -154,6 +157,11 @@ define DEF_THIRD_PARTY_TARGETS ifeq ($$(CFG_WINDOWSY_$(1)), 1) LIBUV_OSTYPE_$(1) := win + # This isn't necessarily a desired option, but it's harmless and works around + # what appears to be a mingw-w64 bug. + # + # https://sourceforge.net/p/mingw-w64/bugs/395/ + JEMALLOC_ARGS_$(1) := --enable-lazy-lock else ifeq ($(OSTYPE_$(1)), apple-darwin) LIBUV_OSTYPE_$(1) := mac else ifeq ($(OSTYPE_$(1)), unknown-freebsd) @@ -161,6 +169,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 @@ -220,6 +229,41 @@ $$(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_s) +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 "$$(JEMALLOC_BUILD_DIR_$(1))"; "$(S)src/jemalloc/configure" \ + $$(JEMALLOC_ARGS_$(1)) --enable-cc-silence --with-jemalloc-prefix=je_ \ + --disable-experimental --build=$(CFG_BUILD) --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 ################################################################################ diff --git a/mk/tests.mk b/mk/tests.mk index 012ec0e862d..71d56d11a73 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -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/rt/hoedown' -v \ | grep '^$(S)src/gyp' -v \ | grep '^$(S)src/etc' -v \ diff --git a/src/jemalloc b/src/jemalloc new file mode 160000 index 00000000000..6a96910f2ea --- /dev/null +++ b/src/jemalloc @@ -0,0 +1 @@ +Subproject commit 6a96910f2eaea6d2c705bb12379b23576b30d7d5 diff --git a/src/libstd/rt/heap.rs b/src/libstd/rt/heap.rs new file mode 100644 index 00000000000..b4b44fbf5c7 --- /dev/null +++ b/src/libstd/rt/heap.rs @@ -0,0 +1,97 @@ +// 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 or the MIT license +// , 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")] +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; +} + +// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough +#[cfg(not(windows))] +#[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 } +} diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 5b9c314d42b..904921cfa18 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -89,7 +89,10 @@ mod macros; // The global (exchange) heap. pub mod global_heap; -// Implementations of language-critical runtime features like @. +/// The low-level memory allocation API. +pub mod heap; + +/// Implementations of language-critical runtime features like @. pub mod task; // The EventLoop and internal synchronous I/O interface.