implemented enabling sized-delete support at runtime

Under gcc 4.5 or greater we're using ifunc function attribute to resolve
sized delete operator to either plain delete implementation (default) or
to sized delete (if enabled via environment variable
TCMALLOC_ENABLE_SIZED_DELETE).
This commit is contained in:
Aliaksey Kandratsenka 2015-10-24 23:16:45 -07:00
parent c2a79d063c
commit 6fdfc5a7f4
3 changed files with 69 additions and 4 deletions

View File

@ -323,6 +323,16 @@ AC_CACHE_CHECK([if the compiler supports -Wno-unused-result],
AM_CONDITIONAL(HAVE_W_NO_UNUSED_RESULT,
test "$perftools_cv_w_no_unused_result" = yes)
AC_ARG_ENABLE([dynamic-sized-delete-support],
[AS_HELP_STRING([--disable-dynamic-sized-delete-support],
[don't try to build run-time switch for sized delete operator])],
[enable_dyn_sized_delete="$enableval"],
[enable_dyn_sized_delete=yes])
AS_IF([test "x$enable_dyn_sized_delete" = xyes],
[AC_DEFINE([ENABLE_DYNAMIC_SIZED_DELETE], 1,
[Build runtime detection for sized delete])])
AC_ARG_ENABLE([sized-delete],
[AS_HELP_STRING([--enable-sized-delete],
[build sized delete operator])],
@ -333,14 +343,14 @@ AS_IF([test "x$enable_sized_delete" = xyes],
AC_MSG_NOTICE([Will build sized deallocation operators])],
[AC_MSG_NOTICE([Will not build sized deallocation operators])])
AS_IF([test "x$enable_sized_delete" = xyes],
AS_IF([test "x$enable_sized_delete" = xyes -o "x$enable_dyn_sized_delete" = xyes],
[AC_CACHE_CHECK([if C++ compiler supports -fsized-deallocation],
perftools_cv_sized_deallocation_result,
[AC_LANG_PUSH(C++)
OLD_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS -fsized-deallocation"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,)],
perftools_cv_sized_deallocation_result="$enable_sized_delete",
perftools_cv_sized_deallocation_result=yes,
perftools_cv_sized_deallocation_result=no)
CXXFLAGS="$OLD_CXXFLAGS"
AC_LANG_POP(C++)])])

View File

@ -44,6 +44,9 @@
#endif
#include <gperftools/tcmalloc.h>
#include "getenv_safe.h" // TCMallocGetenvSafe
#include "base/commandlineflags.h"
#ifndef __THROW // I guess we're not on a glibc-like system
# define __THROW // __THROW is just an optimization, so ok to make it ""
#endif
@ -71,12 +74,60 @@ void operator delete(void* p, const std::nothrow_t& nt) __THROW
void operator delete[](void* p, const std::nothrow_t& nt) __THROW
ALIAS(tc_deletearray_nothrow);
#ifdef ENABLE_SIZED_DELETE
#if defined(ENABLE_SIZED_DELETE)
void operator delete(void *p, size_t size) throw()
ALIAS(tc_delete_sized);
void operator delete[](void *p, size_t size) throw()
ALIAS(tc_deletearray_sized);
#endif
#elif defined(ENABLE_DYNAMIC_SIZED_DELETE) && \
(__GNUC__ * 100 + __GNUC_MINOR__) >= 405
static void delegate_sized_delete(void *p, size_t s) throw() {
(operator delete)(p);
}
static void delegate_sized_deletearray(void *p, size_t s) throw() {
(operator delete[])(p);
}
extern "C" __attribute__((weak))
int tcmalloc_sized_delete_enabled(void);
static bool sized_delete_enabled(void) {
if (tcmalloc_sized_delete_enabled != 0) {
return !!tcmalloc_sized_delete_enabled();
}
const char *flag = TCMallocGetenvSafe("TCMALLOC_ENABLE_SIZED_DELETE");
return tcmalloc::commandlineflags::StringToBool(flag, false);
}
extern "C" {
static void *resolve_delete_sized(void) {
if (sized_delete_enabled()) {
return reinterpret_cast<void *>(tc_delete_sized);
}
return reinterpret_cast<void *>(delegate_sized_delete);
}
static void *resolve_deletearray_sized(void) {
if (sized_delete_enabled()) {
return reinterpret_cast<void *>(tc_deletearray_sized);
}
return reinterpret_cast<void *>(delegate_sized_deletearray);
}
}
void operator delete(void *p, size_t size) throw()
__attribute__((ifunc("resolve_delete_sized")));
void operator delete[](void *p, size_t size) throw()
__attribute__((ifunc("resolve_deletearray_sized")));
#endif /* !ENABLE_SIZED_DELETE && !ENABLE_DYN_SIZED_DELETE */
extern "C" {
void* malloc(size_t size) __THROW ALIAS(tc_malloc);

View File

@ -77,4 +77,8 @@ echo -n "Testing $TCMALLOC_UNITTEST with TCMALLOC_HEAP_LIMIT_MB=512 ... "
TCMALLOC_HEAP_LIMIT_MB=512 run_unittest
echo -n "Testing $TCMALLOC_UNITTEST with TCMALLOC_ENABLE_SIZED_DELETE=t ..."
TCMALLOC_ENABLE_SIZED_DELETE=t run_unittest
echo "PASS"