| Index: third_party/tcmalloc/chromium/src/tcmalloc.cc
|
| ===================================================================
|
| --- third_party/tcmalloc/chromium/src/tcmalloc.cc (revision 41940)
|
| +++ third_party/tcmalloc/chromium/src/tcmalloc.cc (working copy)
|
| @@ -124,6 +124,7 @@
|
| #include "linked_list.h"
|
| #include "maybe_threads.h"
|
| #include "page_heap.h"
|
| +#include "page_heap_allocator.h"
|
| #include "pagemap.h"
|
| #include "span.h"
|
| #include "static_vars.h"
|
| @@ -135,8 +136,8 @@
|
| # define WIN32_DO_PATCHING 1
|
| #endif
|
|
|
| -using std::max;
|
| using tcmalloc::PageHeap;
|
| +using tcmalloc::PageHeapAllocator;
|
| using tcmalloc::SizeMap;
|
| using tcmalloc::Span;
|
| using tcmalloc::StackTrace;
|
| @@ -228,30 +229,23 @@
|
| ATTRIBUTE_SECTION(google_malloc);
|
| void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) __THROW
|
| ATTRIBUTE_SECTION(google_malloc);
|
| - // Surprisingly, compilers use a nothrow-delete internally. See, eg:
|
| - // http://www.dinkumware.com/manuals/?manual=compleat&page=new.html
|
| - void tc_delete_nothrow(void* ptr, const std::nothrow_t&) __THROW
|
| - ATTRIBUTE_SECTION(google_malloc);
|
| - void tc_deletearray_nothrow(void* ptr, const std::nothrow_t&) __THROW
|
| - ATTRIBUTE_SECTION(google_malloc);
|
| -} // extern "C"
|
| +}
|
|
|
| // Override the libc functions to prefer our own instead. This comes
|
| // first so code in tcmalloc.cc can use the overridden versions. One
|
| // exception: in windows, by default, we patch our code into these
|
| // functions (via src/windows/patch_function.cc) rather than override
|
| // them. In that case, we don't want to do this overriding here.
|
| -#if !defined(WIN32_DO_PATCHING) && !defined(TCMALLOC_FOR_DEBUGALLOCATION)
|
| +#ifndef WIN32_DO_PATCHING
|
|
|
| // TODO(mbelshe): Turn off TCMalloc's symbols for libc. We do that
|
| // elsewhere.
|
| -#ifndef _WIN32
|
| +#if 0
|
|
|
| #if defined(__GNUC__) && !defined(__MACH__)
|
| // Potentially faster variants that use the gcc alias extension.
|
| + // Mach-O (Darwin) does not support weak aliases, hence the __MACH__ check.
|
| // FreeBSD does support aliases, but apparently not correctly. :-(
|
| - // NOTE: we make many of these symbols weak, but do so in the makefile
|
| - // (via objcopy -W) and not here. That ends up being more portable.
|
| # define ALIAS(x) __attribute__ ((alias (x)))
|
| void* operator new(size_t size) ALIAS("tc_new");
|
| void operator delete(void* p) __THROW ALIAS("tc_delete");
|
| @@ -261,10 +255,6 @@
|
| ALIAS("tc_new_nothrow");
|
| void* operator new[](size_t size, const std::nothrow_t&) __THROW
|
| ALIAS("tc_newarray_nothrow");
|
| -void operator delete(void* size, const std::nothrow_t&) __THROW
|
| - ALIAS("tc_delete_nothrow");
|
| -void operator delete[](void* size, const std::nothrow_t&) __THROW
|
| - ALIAS("tc_deletearray_nothrow");
|
| extern "C" {
|
| void* malloc(size_t size) __THROW ALIAS("tc_malloc");
|
| void free(void* ptr) __THROW ALIAS("tc_free");
|
| @@ -281,8 +271,26 @@
|
| #ifdef HAVE_STRUCT_MALLINFO
|
| struct mallinfo mallinfo(void) __THROW ALIAS("tc_mallinfo");
|
| #endif
|
| + // Some library routines on RedHat 9 allocate memory using malloc()
|
| + // and free it using __libc_free() (or vice-versa). Since we provide
|
| + // our own implementations of malloc/free, we need to make sure that
|
| + // the __libc_XXX variants (defined as part of glibc) also point to
|
| + // the same implementations.
|
| +# if defined(__GLIBC__)
|
| + void* __libc_malloc(size_t size) ALIAS("tc_malloc");
|
| + void __libc_free(void* ptr) ALIAS("tc_free");
|
| + void* __libc_realloc(void* ptr, size_t size) ALIAS("tc_realloc");
|
| + void* __libc_calloc(size_t n, size_t size) ALIAS("tc_calloc");
|
| + void __libc_cfree(void* ptr) ALIAS("tc_cfree");
|
| + void* __libc_memalign(size_t align, size_t s) ALIAS("tc_memalign");
|
| + void* __libc_valloc(size_t size) ALIAS("tc_valloc");
|
| + void* __libc_pvalloc(size_t size) ALIAS("tc_pvalloc");
|
| + int __posix_memalign(void** r, size_t a, size_t s) ALIAS("tc_posix_memalign");
|
| +# define HAVE_ALIASED___LIBC 1
|
| +# endif // #if defined(__GLIBC__)
|
| } // extern "C"
|
| -#else // #if defined(__GNUC__) && !defined(__MACH__)
|
| +# undef ALIAS
|
| +#else
|
| // Portable wrappers
|
| void* operator new(size_t size) { return tc_new(size); }
|
| void operator delete(void* p) __THROW { tc_delete(p); }
|
| @@ -294,12 +302,6 @@
|
| void* operator new[](size_t size, const std::nothrow_t& nt) __THROW {
|
| return tc_newarray_nothrow(size, nt);
|
| }
|
| -void operator delete(void* ptr, const std::nothrow_t& nt) __THROW {
|
| - return tc_delete_nothrow(ptr, nt);
|
| -}
|
| -void operator delete[](void* ptr, const std::nothrow_t& nt) __THROW {
|
| - return tc_deletearray_nothrow(ptr, nt);
|
| -}
|
| extern "C" {
|
| void* malloc(size_t s) __THROW { return tc_malloc(s); }
|
| void free(void* p) __THROW { tc_free(p); }
|
| @@ -317,27 +319,11 @@
|
| #ifdef HAVE_STRUCT_MALLINFO
|
| struct mallinfo mallinfo(void) __THROW { return tc_mallinfo(); }
|
| #endif
|
| -} // extern "C"
|
| +} // extern C
|
| #endif // #if defined(__GNUC__)
|
|
|
| -// Some library routines on RedHat 9 allocate memory using malloc()
|
| -// and free it using __libc_free() (or vice-versa). Since we provide
|
| -// our own implementations of malloc/free, we need to make sure that
|
| -// the __libc_XXX variants (defined as part of glibc) also point to
|
| -// the same implementations.
|
| -#ifdef __GLIBC__ // only glibc defines __libc_*
|
| +#ifndef HAVE_ALIASED___LIBC
|
| extern "C" {
|
| -#ifdef ALIAS
|
| - void* __libc_malloc(size_t size) ALIAS("tc_malloc");
|
| - void __libc_free(void* ptr) ALIAS("tc_free");
|
| - void* __libc_realloc(void* ptr, size_t size) ALIAS("tc_realloc");
|
| - void* __libc_calloc(size_t n, size_t size) ALIAS("tc_calloc");
|
| - void __libc_cfree(void* ptr) ALIAS("tc_cfree");
|
| - void* __libc_memalign(size_t align, size_t s) ALIAS("tc_memalign");
|
| - void* __libc_valloc(size_t size) ALIAS("tc_valloc");
|
| - void* __libc_pvalloc(size_t size) ALIAS("tc_pvalloc");
|
| - int __posix_memalign(void** r, size_t a, size_t s) ALIAS("tc_posix_memalign");
|
| -#else // #ifdef ALIAS
|
| void* __libc_malloc(size_t size) { return malloc(size); }
|
| void __libc_free(void* ptr) { free(ptr); }
|
| void* __libc_realloc(void* ptr, size_t size) { return realloc(ptr, size); }
|
| @@ -349,25 +335,19 @@
|
| int __posix_memalign(void** r, size_t a, size_t s) {
|
| return posix_memalign(r, a, s);
|
| }
|
| -#endif // #ifdef ALIAS
|
| } // extern "C"
|
| -#endif // ifdef __GLIBC__
|
| +#endif // #ifndef HAVE_ALIASED___LIBC
|
|
|
| -#endif // #ifndef _WIN32
|
| -#undef ALIAS
|
| +#endif // #ifdef 0
|
|
|
| -#endif // #ifndef(WIN32_DO_PATCHING) && ndef(TCMALLOC_FOR_DEBUGALLOCATION)
|
| +#endif // #ifndef WIN32_DO_PATCHING
|
|
|
|
|
| // ----------------------- IMPLEMENTATION -------------------------------
|
|
|
| -static int tc_new_mode = 0; // See tc_set_new_mode().
|
| -
|
| -// Routines such as free() and realloc() catch some erroneous pointers
|
| -// passed to them, and invoke the below when they do. (An erroneous pointer
|
| -// won't be caught if it's within a valid span or a stale span for which
|
| -// the pagemap cache has a non-zero sizeclass.) This is a cheap (source-editing
|
| -// required) kind of exception handling for these routines.
|
| +// These routines are called by free(), realloc(), etc. if the pointer is
|
| +// invalid. This is a cheap (source-editing required) kind of exception
|
| +// handling for these routines.
|
| namespace {
|
| void InvalidFree(void* ptr) {
|
| CRASH("Attempt to free invalid pointer: %p\n", ptr);
|
| @@ -386,11 +366,13 @@
|
|
|
| // Extract interesting stats
|
| struct TCMallocStats {
|
| - uint64_t thread_bytes; // Bytes in thread caches
|
| - uint64_t central_bytes; // Bytes in central cache
|
| - uint64_t transfer_bytes; // Bytes in central transfer cache
|
| - uint64_t metadata_bytes; // Bytes alloced for metadata
|
| - PageHeap::Stats pageheap; // Stats from page heap
|
| + uint64_t system_bytes; // Bytes alloced from system
|
| + uint64_t committed_bytes; // Bytes alloced and committed from system
|
| + uint64_t thread_bytes; // Bytes in thread caches
|
| + uint64_t central_bytes; // Bytes in central cache
|
| + uint64_t transfer_bytes; // Bytes in central transfer cache
|
| + uint64_t pageheap_bytes; // Bytes in page heap
|
| + uint64_t metadata_bytes; // Bytes alloced for metadata
|
| };
|
|
|
| // Get stats into "r". Also get per-size-class counts if class_count != NULL
|
| @@ -412,8 +394,14 @@
|
| { // scope
|
| SpinLockHolder h(Static::pageheap_lock());
|
| ThreadCache::GetThreadStats(&r->thread_bytes, class_count);
|
| + }
|
| +
|
| + { //scope
|
| + SpinLockHolder h(Static::pageheap_lock());
|
| + r->system_bytes = Static::pageheap()->SystemBytes();
|
| + r->committed_bytes = Static::pageheap()->CommittedBytes();
|
| r->metadata_bytes = tcmalloc::metadata_system_bytes();
|
| - r->pageheap = Static::pageheap()->stats();
|
| + r->pageheap_bytes = Static::pageheap()->FreeBytes();
|
| }
|
| }
|
|
|
| @@ -425,9 +413,8 @@
|
|
|
| static const double MB = 1048576.0;
|
|
|
| - const uint64_t bytes_in_use = stats.pageheap.system_bytes
|
| - - stats.pageheap.free_bytes
|
| - - stats.pageheap.unmapped_bytes
|
| + const uint64_t bytes_in_use = stats.system_bytes
|
| + - stats.pageheap_bytes
|
| - stats.central_bytes
|
| - stats.transfer_bytes
|
| - stats.thread_bytes;
|
| @@ -435,15 +422,13 @@
|
| out->printf("WASTE: %7.1f MB committed but not used\n"
|
| "WASTE: %7.1f MB bytes committed, %7.1f MB bytes in use\n"
|
| "WASTE: committed/used ratio of %f\n",
|
| - (stats.pageheap.committed_bytes - bytes_in_use) / MB,
|
| - stats.pageheap.committed_bytes / MB,
|
| + (stats.committed_bytes - bytes_in_use) / MB,
|
| + stats.committed_bytes / MB,
|
| bytes_in_use / MB,
|
| - stats.pageheap.committed_bytes / static_cast<double>(bytes_in_use));
|
| + stats.committed_bytes / static_cast<double>(bytes_in_use));
|
|
|
| if (level >= 2) {
|
| out->printf("------------------------------------------------\n");
|
| - out->printf("Size class breakdown\n");
|
| - out->printf("------------------------------------------------\n");
|
| uint64_t cumulative = 0;
|
| for (int cl = 0; cl < kNumClasses; ++cl) {
|
| if (class_count[cl] > 0) {
|
| @@ -471,7 +456,6 @@
|
| "MALLOC: %12" PRIu64 " (%7.1f MB) Bytes committed\n"
|
| "MALLOC: %12" PRIu64 " (%7.1f MB) Bytes in use by application\n"
|
| "MALLOC: %12" PRIu64 " (%7.1f MB) Bytes free in page heap\n"
|
| - "MALLOC: %12" PRIu64 " (%7.1f MB) Bytes unmapped in page heap\n"
|
| "MALLOC: %12" PRIu64 " (%7.1f MB) Bytes free in central cache\n"
|
| "MALLOC: %12" PRIu64 " (%7.1f MB) Bytes free in transfer cache\n"
|
| "MALLOC: %12" PRIu64 " (%7.1f MB) Bytes free in thread caches\n"
|
| @@ -479,11 +463,10 @@
|
| "MALLOC: %12" PRIu64 " Thread heaps in use\n"
|
| "MALLOC: %12" PRIu64 " (%7.1f MB) Metadata allocated\n"
|
| "------------------------------------------------\n",
|
| - stats.pageheap.system_bytes, stats.pageheap.system_bytes / MB,
|
| - stats.pageheap.committed_bytes, stats.pageheap.committed_bytes / MB,
|
| + stats.system_bytes, stats.system_bytes / MB,
|
| + stats.committed_bytes, stats.committed_bytes / MB,
|
| bytes_in_use, bytes_in_use / MB,
|
| - stats.pageheap.free_bytes, stats.pageheap.free_bytes / MB,
|
| - stats.pageheap.unmapped_bytes, stats.pageheap.unmapped_bytes / MB,
|
| + stats.pageheap_bytes, stats.pageheap_bytes / MB,
|
| stats.central_bytes, stats.central_bytes / MB,
|
| stats.transfer_bytes, stats.transfer_bytes / MB,
|
| stats.thread_bytes, stats.thread_bytes / MB,
|
| @@ -547,50 +530,9 @@
|
| return result;
|
| }
|
|
|
| -static void IterateOverRanges(void* arg, MallocExtension::RangeFunction func) {
|
| - PageID page = 1; // Some code may assume that page==0 is never used
|
| - bool done = false;
|
| - while (!done) {
|
| - // Accumulate a small number of ranges in a local buffer
|
| - static const int kNumRanges = 16;
|
| - static base::MallocRange ranges[kNumRanges];
|
| - int n = 0;
|
| - {
|
| - SpinLockHolder h(Static::pageheap_lock());
|
| - while (n < kNumRanges) {
|
| - if (!Static::pageheap()->GetNextRange(page, &ranges[n])) {
|
| - done = true;
|
| - break;
|
| - } else {
|
| - uintptr_t limit = ranges[n].address + ranges[n].length;
|
| - page = (limit + kPageSize - 1) >> kPageShift;
|
| - n++;
|
| - }
|
| - }
|
| - }
|
| -
|
| - for (int i = 0; i < n; i++) {
|
| - (*func)(arg, &ranges[i]);
|
| - }
|
| - }
|
| -}
|
| -
|
| // TCMalloc's support for extra malloc interfaces
|
| class TCMallocImplementation : public MallocExtension {
|
| - private:
|
| - // ReleaseToSystem() might release more than the requested bytes because
|
| - // the page heap releases at the span granularity, and spans are of wildly
|
| - // different sizes. This member keeps track of the extra bytes bytes
|
| - // released so that the app can periodically call ReleaseToSystem() to
|
| - // release memory at a constant rate.
|
| - // NOTE: Protected by Static::pageheap_lock().
|
| - size_t extra_bytes_released_;
|
| -
|
| public:
|
| - TCMallocImplementation()
|
| - : extra_bytes_released_(0) {
|
| - }
|
| -
|
| virtual void GetStats(char* buffer, int buffer_length) {
|
| ASSERT(buffer_length > 0);
|
| TCMalloc_Printer printer(buffer, buffer_length);
|
| @@ -620,54 +562,42 @@
|
| return DumpHeapGrowthStackTraces();
|
| }
|
|
|
| - virtual void Ranges(void* arg, RangeFunction func) {
|
| - IterateOverRanges(arg, func);
|
| - }
|
| -
|
| virtual bool GetNumericProperty(const char* name, size_t* value) {
|
| ASSERT(name != NULL);
|
|
|
| if (strcmp(name, "generic.current_allocated_bytes") == 0) {
|
| TCMallocStats stats;
|
| ExtractStats(&stats, NULL);
|
| - *value = stats.pageheap.system_bytes
|
| + *value = stats.system_bytes
|
| - stats.thread_bytes
|
| - stats.central_bytes
|
| - stats.transfer_bytes
|
| - - stats.pageheap.free_bytes
|
| - - stats.pageheap.unmapped_bytes;
|
| + - stats.pageheap_bytes;
|
| return true;
|
| }
|
|
|
| if (strcmp(name, "generic.heap_size") == 0) {
|
| TCMallocStats stats;
|
| ExtractStats(&stats, NULL);
|
| - *value = stats.pageheap.system_bytes;
|
| + *value = stats.system_bytes;
|
| return true;
|
| }
|
|
|
| - if (strcmp(name, "tcmalloc.slack_bytes") == 0) {
|
| - // We assume that bytes in the page heap are not fragmented too
|
| - // badly, and are therefore available for allocation without
|
| - // growing the pageheap system byte count.
|
| - SpinLockHolder l(Static::pageheap_lock());
|
| - PageHeap::Stats stats = Static::pageheap()->stats();
|
| - *value = stats.free_bytes + stats.unmapped_bytes;
|
| + if (strcmp(name, "generic.committed_bytes") == 0) {
|
| + TCMallocStats stats;
|
| + ExtractStats(&stats, NULL);
|
| + *value = stats.committed_bytes + stats.metadata_bytes;
|
| return true;
|
| }
|
|
|
| - if (strcmp(name, "tcmalloc.pageheap_free_bytes") == 0) {
|
| + if (strcmp(name, "tcmalloc.slack_bytes") == 0) {
|
| + // We assume that bytes in the page heap are not fragmented too
|
| + // badly, and are therefore available for allocation.
|
| SpinLockHolder l(Static::pageheap_lock());
|
| - *value = Static::pageheap()->stats().free_bytes;
|
| + *value = Static::pageheap()->FreeBytes();
|
| return true;
|
| }
|
|
|
| - if (strcmp(name, "tcmalloc.pageheap_unmapped_bytes") == 0) {
|
| - SpinLockHolder l(Static::pageheap_lock());
|
| - *value = Static::pageheap()->stats().unmapped_bytes;
|
| - return true;
|
| - }
|
| -
|
| if (strcmp(name, "tcmalloc.max_total_thread_cache_bytes") == 0) {
|
| SpinLockHolder l(Static::pageheap_lock());
|
| *value = ThreadCache::overall_thread_cache_size();
|
| @@ -700,31 +630,9 @@
|
| ThreadCache::BecomeIdle();
|
| }
|
|
|
| - virtual void MarkThreadBusy(); // Implemented below
|
| -
|
| - virtual void ReleaseToSystem(size_t num_bytes) {
|
| + virtual void ReleaseFreeMemory() {
|
| SpinLockHolder h(Static::pageheap_lock());
|
| - if (num_bytes <= extra_bytes_released_) {
|
| - // We released too much on a prior call, so don't release any
|
| - // more this time.
|
| - extra_bytes_released_ = extra_bytes_released_ - num_bytes;
|
| - return;
|
| - }
|
| - num_bytes = num_bytes - extra_bytes_released_;
|
| - // num_bytes might be less than one page. If we pass zero to
|
| - // ReleaseAtLeastNPages, it won't do anything, so we release a whole
|
| - // page now and let extra_bytes_released_ smooth it out over time.
|
| - Length num_pages = max<Length>(num_bytes >> kPageShift, 1);
|
| - size_t bytes_released = Static::pageheap()->ReleaseAtLeastNPages(
|
| - num_pages) << kPageShift;
|
| - if (bytes_released > num_bytes) {
|
| - extra_bytes_released_ = bytes_released - num_bytes;
|
| - } else {
|
| - // The PageHeap wasn't able to release num_bytes. Don't try to
|
| - // compensate with a big release next time. Specifically,
|
| - // ReleaseFreeMemory() calls ReleaseToSystem(LONG_MAX).
|
| - extra_bytes_released_ = 0;
|
| - }
|
| + Static::pageheap()->ReleaseFreePages();
|
| }
|
|
|
| virtual void SetMemoryReleaseRate(double rate) {
|
| @@ -773,9 +681,9 @@
|
| // patch the windows VirtualAlloc, etc.
|
| PatchWindowsFunctions(); // defined in windows/patch_functions.cc
|
| #endif
|
| - tc_free(tc_malloc(1));
|
| + free(malloc(1));
|
| ThreadCache::InitTSD();
|
| - tc_free(tc_malloc(1));
|
| + free(malloc(1));
|
| MallocExtension::Register(new TCMallocImplementation);
|
| }
|
| }
|
| @@ -870,24 +778,6 @@
|
|
|
| namespace {
|
|
|
| -inline void* cpp_alloc(size_t size, bool nothrow);
|
| -inline void* do_malloc(size_t size);
|
| -
|
| -// TODO(willchan): Investigate whether or not inlining this much is harmful to
|
| -// performance.
|
| -// This is equivalent to do_malloc() except when tc_new_mode is set to true.
|
| -// Otherwise, it will run the std::new_handler if set.
|
| -inline void* do_malloc_or_cpp_alloc(size_t size) {
|
| - return tc_new_mode ? cpp_alloc(size, true) : do_malloc(size);
|
| -}
|
| -
|
| -void* cpp_memalign(size_t align, size_t size);
|
| -void* do_memalign(size_t align, size_t size);
|
| -
|
| -inline void* do_memalign_or_cpp_memalign(size_t align, size_t size) {
|
| - return tc_new_mode ? cpp_memalign(align, size) : do_memalign(align, size);
|
| -}
|
| -
|
| // Helper for do_malloc().
|
| inline void* do_malloc_pages(Length num_pages) {
|
| Span *span;
|
| @@ -938,7 +828,7 @@
|
| const size_t size = n * elem_size;
|
| if (elem_size != 0 && size / elem_size != n) return NULL;
|
|
|
| - void* result = do_malloc_or_cpp_alloc(size);
|
| + void* result = do_malloc(size);
|
| if (result != NULL) {
|
| memset(result, 0, size);
|
| }
|
| @@ -1047,11 +937,11 @@
|
| void* new_ptr = NULL;
|
|
|
| if (new_size > old_size && new_size < lower_bound_to_grow) {
|
| - new_ptr = do_malloc_or_cpp_alloc(lower_bound_to_grow);
|
| + new_ptr = do_malloc(lower_bound_to_grow);
|
| }
|
| if (new_ptr == NULL) {
|
| // Either new_size is not a tiny increment, or last do_malloc failed.
|
| - new_ptr = do_malloc_or_cpp_alloc(new_size);
|
| + new_ptr = do_malloc(new_size);
|
| }
|
| if (new_ptr == NULL) {
|
| return NULL;
|
| @@ -1172,18 +1062,16 @@
|
|
|
| // Unfortunately, the struct contains "int" field, so some of the
|
| // size values will be truncated.
|
| - info.arena = static_cast<int>(stats.pageheap.system_bytes);
|
| + info.arena = static_cast<int>(stats.system_bytes);
|
| info.fsmblks = static_cast<int>(stats.thread_bytes
|
| + stats.central_bytes
|
| + stats.transfer_bytes);
|
| - info.fordblks = static_cast<int>(stats.pageheap.free_bytes +
|
| - stats.pageheap.unmapped_bytes);
|
| - info.uordblks = static_cast<int>(stats.pageheap.system_bytes
|
| + info.fordblks = static_cast<int>(stats.pageheap_bytes);
|
| + info.uordblks = static_cast<int>(stats.system_bytes
|
| - stats.thread_bytes
|
| - stats.central_bytes
|
| - stats.transfer_bytes
|
| - - stats.pageheap.free_bytes
|
| - - stats.pageheap.unmapped_bytes);
|
| + - stats.pageheap_bytes);
|
|
|
| return info;
|
| }
|
| @@ -1239,52 +1127,6 @@
|
| }
|
| }
|
|
|
| -void* cpp_memalign(size_t align, size_t size) {
|
| - for (;;) {
|
| - void* p = do_memalign(align, size);
|
| -#ifdef PREANSINEW
|
| - return p;
|
| -#else
|
| - if (p == NULL) { // allocation failed
|
| - // Get the current new handler. NB: this function is not
|
| - // thread-safe. We make a feeble stab at making it so here, but
|
| - // this lock only protects against tcmalloc interfering with
|
| - // itself, not with other libraries calling set_new_handler.
|
| - std::new_handler nh;
|
| - {
|
| - SpinLockHolder h(&set_new_handler_lock);
|
| - nh = std::set_new_handler(0);
|
| - (void) std::set_new_handler(nh);
|
| - }
|
| -#if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)
|
| - if (nh) {
|
| - // Since exceptions are disabled, we don't really know if new_handler
|
| - // failed. Assume it will abort if it fails.
|
| - (*nh)();
|
| - continue;
|
| - }
|
| - return 0;
|
| -#else
|
| - // If no new_handler is established, the allocation failed.
|
| - if (!nh)
|
| - return 0;
|
| -
|
| - // Otherwise, try the new_handler. If it returns, retry the
|
| - // allocation. If it throws std::bad_alloc, fail the allocation.
|
| - // if it throws something else, don't interfere.
|
| - try {
|
| - (*nh)();
|
| - } catch (const std::bad_alloc&) {
|
| - return p;
|
| - }
|
| -#endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)
|
| - } else { // allocation success
|
| - return p;
|
| - }
|
| -#endif // PREANSINEW
|
| - }
|
| -}
|
| -
|
| } // end unnamed namespace
|
|
|
| // As promised, the definition of this function, declared above.
|
| @@ -1292,56 +1134,41 @@
|
| return GetSizeWithCallback(ptr, &InvalidGetAllocatedSize);
|
| }
|
|
|
| -void TCMallocImplementation::MarkThreadBusy() {
|
| - // Allocate to force the creation of a thread cache, but avoid
|
| - // invoking any hooks.
|
| - do_free(do_malloc(0));
|
| -}
|
| -
|
| //-------------------------------------------------------------------
|
| // Exported routines
|
| //-------------------------------------------------------------------
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL const char* tc_version(
|
| - int* major, int* minor, const char** patch) __THROW {
|
| - if (major) *major = TC_VERSION_MAJOR;
|
| - if (minor) *minor = TC_VERSION_MINOR;
|
| - if (patch) *patch = TC_VERSION_PATCH;
|
| - return TC_VERSION_STRING;
|
| -}
|
| -
|
| // CAVEAT: The code structure below ensures that MallocHook methods are always
|
| // called from the stack frame of the invoked allocation function.
|
| // heap-checker.cc depends on this to start a stack trace from
|
| // the call to the (de)allocation function.
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) __THROW {
|
| - void* result = do_malloc_or_cpp_alloc(size);
|
| +static int tc_new_mode = 0; // See tc_set_new_mode().
|
| +extern "C" void* tc_malloc(size_t size) __THROW {
|
| + void* result = (tc_new_mode ? cpp_alloc(size, false) : do_malloc(size));
|
| MallocHook::InvokeNewHook(result, size);
|
| return result;
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void tc_free(void* ptr) __THROW {
|
| +extern "C" void tc_free(void* ptr) __THROW {
|
| MallocHook::InvokeDeleteHook(ptr);
|
| do_free(ptr);
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void* tc_calloc(size_t n,
|
| - size_t elem_size) __THROW {
|
| +extern "C" void* tc_calloc(size_t n, size_t elem_size) __THROW {
|
| void* result = do_calloc(n, elem_size);
|
| MallocHook::InvokeNewHook(result, n * elem_size);
|
| return result;
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) __THROW {
|
| +extern "C" void tc_cfree(void* ptr) __THROW {
|
| MallocHook::InvokeDeleteHook(ptr);
|
| do_free(ptr);
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void* tc_realloc(void* old_ptr,
|
| - size_t new_size) __THROW {
|
| +extern "C" void* tc_realloc(void* old_ptr, size_t new_size) __THROW {
|
| if (old_ptr == NULL) {
|
| - void* result = do_malloc_or_cpp_alloc(new_size);
|
| + void* result = do_malloc(new_size);
|
| MallocHook::InvokeNewHook(result, new_size);
|
| return result;
|
| }
|
| @@ -1353,7 +1180,7 @@
|
| return do_realloc(old_ptr, new_size);
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void* tc_new(size_t size) {
|
| +extern "C" void* tc_new(size_t size) {
|
| void* p = cpp_alloc(size, false);
|
| // We keep this next instruction out of cpp_alloc for a reason: when
|
| // it's in, and new just calls cpp_alloc, the optimizer may fold the
|
| @@ -1364,27 +1191,18 @@
|
| return p;
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void* tc_new_nothrow(
|
| - size_t size, const std::nothrow_t&) __THROW {
|
| +extern "C" void* tc_new_nothrow(size_t size, const std::nothrow_t&) __THROW {
|
| void* p = cpp_alloc(size, true);
|
| MallocHook::InvokeNewHook(p, size);
|
| return p;
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW {
|
| +extern "C" void tc_delete(void* p) __THROW {
|
| MallocHook::InvokeDeleteHook(p);
|
| do_free(p);
|
| }
|
|
|
| -// Compilers define and use this (via ::operator delete(ptr, nothrow)).
|
| -// But it's really the same as normal delete, so we just do the same thing.
|
| -extern "C" PERFTOOLS_DLL_DECL void tc_delete_nothrow(
|
| - void* p, const std::nothrow_t&) __THROW {
|
| - MallocHook::InvokeDeleteHook(p);
|
| - do_free(p);
|
| -}
|
| -
|
| -extern "C" PERFTOOLS_DLL_DECL void* tc_newarray(size_t size) {
|
| +extern "C" void* tc_newarray(size_t size) {
|
| void* p = cpp_alloc(size, false);
|
| // We keep this next instruction out of cpp_alloc for a reason: when
|
| // it's in, and new just calls cpp_alloc, the optimizer may fold the
|
| @@ -1395,40 +1213,32 @@
|
| return p;
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(
|
| - size_t size, const std::nothrow_t&) __THROW {
|
| +extern "C" void* tc_newarray_nothrow(size_t size, const std::nothrow_t&) __THROW {
|
| void* p = cpp_alloc(size, true);
|
| MallocHook::InvokeNewHook(p, size);
|
| return p;
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW {
|
| +extern "C" void tc_deletearray(void* p) __THROW {
|
| MallocHook::InvokeDeleteHook(p);
|
| do_free(p);
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(
|
| - void* p, const std::nothrow_t&) __THROW {
|
| - MallocHook::InvokeDeleteHook(p);
|
| - do_free(p);
|
| -}
|
| -
|
| -extern "C" PERFTOOLS_DLL_DECL void* tc_memalign(size_t align,
|
| - size_t size) __THROW {
|
| - void* result = do_memalign_or_cpp_memalign(align, size);
|
| +extern "C" void* tc_memalign(size_t align, size_t size) __THROW {
|
| + void* result = do_memalign(align, size);
|
| MallocHook::InvokeNewHook(result, size);
|
| return result;
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL int tc_posix_memalign(
|
| - void** result_ptr, size_t align, size_t size) __THROW {
|
| +extern "C" int tc_posix_memalign(void** result_ptr, size_t align, size_t size)
|
| + __THROW {
|
| if (((align % sizeof(void*)) != 0) ||
|
| ((align & (align - 1)) != 0) ||
|
| (align == 0)) {
|
| return EINVAL;
|
| }
|
|
|
| - void* result = do_memalign_or_cpp_memalign(align, size);
|
| + void* result = do_memalign(align, size);
|
| MallocHook::InvokeNewHook(result, size);
|
| if (result == NULL) {
|
| return ENOMEM;
|
| @@ -1440,36 +1250,33 @@
|
|
|
| static size_t pagesize = 0;
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void* tc_valloc(size_t size) __THROW {
|
| +extern "C" void* tc_valloc(size_t size) __THROW {
|
| // Allocate page-aligned object of length >= size bytes
|
| if (pagesize == 0) pagesize = getpagesize();
|
| - void* result = do_memalign_or_cpp_memalign(pagesize, size);
|
| + void* result = do_memalign(pagesize, size);
|
| MallocHook::InvokeNewHook(result, size);
|
| return result;
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t size) __THROW {
|
| +extern "C" void* tc_pvalloc(size_t size) __THROW {
|
| // Round up size to a multiple of pagesize
|
| if (pagesize == 0) pagesize = getpagesize();
|
| - if (size == 0) { // pvalloc(0) should allocate one page, according to
|
| - size = pagesize; // http://man.free4web.biz/man3/libmpatrol.3.html
|
| - }
|
| size = (size + pagesize - 1) & ~(pagesize - 1);
|
| - void* result = do_memalign_or_cpp_memalign(pagesize, size);
|
| + void* result = do_memalign(pagesize, size);
|
| MallocHook::InvokeNewHook(result, size);
|
| return result;
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL void tc_malloc_stats(void) __THROW {
|
| +extern "C" void tc_malloc_stats(void) __THROW {
|
| do_malloc_stats();
|
| }
|
|
|
| -extern "C" PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) __THROW {
|
| +extern "C" int tc_mallopt(int cmd, int value) __THROW {
|
| return do_mallopt(cmd, value);
|
| }
|
|
|
| #ifdef HAVE_STRUCT_MALLINFO
|
| -extern "C" PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW {
|
| +extern "C" struct mallinfo tc_mallinfo(void) __THROW {
|
| return do_mallinfo();
|
| }
|
| #endif
|
| @@ -1479,7 +1286,7 @@
|
| // If flag is 1, calls to malloc will behave like calls to new,
|
| // and the std_new_handler will be invoked on failure.
|
| // Returns the previous mode.
|
| -extern "C" PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW {
|
| +extern "C" int tc_set_new_mode(int flag) __THROW {
|
| int old_mode = tc_new_mode;
|
| tc_new_mode = flag;
|
| return old_mode;
|
| @@ -1493,15 +1300,13 @@
|
| // This function is an exception to the rule of calling MallocHook method
|
| // from the stack frame of the allocation function;
|
| // heap-checker handles this special case explicitly.
|
| -#ifndef TCMALLOC_FOR_DEBUGALLOCATION
|
| static void *MemalignOverride(size_t align, size_t size, const void *caller)
|
| __THROW ATTRIBUTE_SECTION(google_malloc);
|
|
|
| static void *MemalignOverride(size_t align, size_t size, const void *caller)
|
| __THROW {
|
| - void* result = do_memalign_or_cpp_memalign(align, size);
|
| + void* result = do_memalign(align, size);
|
| MallocHook::InvokeNewHook(result, size);
|
| return result;
|
| }
|
| void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride;
|
| -#endif // #ifndef TCMALLOC_FOR_DEBUGALLOCATION
|
|
|