OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <config.h> |
| 6 |
| 7 // When defined, different heap allocators can be used via an environment |
| 8 // variable set before running the program. This may reduce the amount |
| 9 // of inlining that we get with malloc/free/etc. Disabling makes it |
| 10 // so that only tcmalloc can be used. |
| 11 #define ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 12 |
| 13 // TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth |
| 14 // from the "user code" so that debugging tools (HeapChecker) can work. |
| 15 |
| 16 // __THROW is defined in glibc systems. It means, counter-intuitively, |
| 17 // "This function will never throw an exception." It's an optional |
| 18 // optimization tool, but we may need to use it to match glibc prototypes. |
| 19 #ifndef __THROW // I guess we're not on a glibc system |
| 20 # define __THROW // __THROW is just an optimization, so ok to make it "" |
| 21 #endif |
| 22 |
| 23 // new_mode behaves similarly to MSVC's _set_new_mode. |
| 24 // If flag is 0 (default), calls to malloc will behave normally. |
| 25 // If flag is 1, calls to malloc will behave like calls to new, |
| 26 // and the std_new_handler will be invoked on failure. |
| 27 // Can be set by calling _set_new_mode(). |
| 28 static int new_mode = 0; |
| 29 |
| 30 typedef enum { |
| 31 TCMALLOC, // TCMalloc is the default allocator. |
| 32 JEMALLOC, // JEMalloc |
| 33 WINDEFAULT, // Windows Heap |
| 34 WINLFH, // Windows LFH Heap |
| 35 } Allocator; |
| 36 |
| 37 // This is the default allocator. |
| 38 static Allocator allocator = TCMALLOC; |
| 39 |
| 40 // We include tcmalloc and the win_allocator to get as much inlining as |
| 41 // possible. |
| 42 #include "tcmalloc.cc" |
| 43 #include "win_allocator.cc" |
| 44 |
| 45 // Forward declarations from jemalloc. |
| 46 extern "C" { |
| 47 void* je_malloc(size_t s); |
| 48 void* je_realloc(void* p, size_t s); |
| 49 void je_free(void* s); |
| 50 size_t je_msize(void* p); |
| 51 bool je_malloc_init_hard(); |
| 52 } |
| 53 |
| 54 extern "C" { |
| 55 |
| 56 // Call the new handler, if one has been set. |
| 57 // Returns true on successfully calling the handler, false otherwise. |
| 58 inline bool call_new_handler(bool nothrow) { |
| 59 // Get the current new handler. NB: this function is not |
| 60 // thread-safe. We make a feeble stab at making it so here, but |
| 61 // this lock only protects against tcmalloc interfering with |
| 62 // itself, not with other libraries calling set_new_handler. |
| 63 std::new_handler nh; |
| 64 { |
| 65 SpinLockHolder h(&set_new_handler_lock); |
| 66 nh = std::set_new_handler(0); |
| 67 (void) std::set_new_handler(nh); |
| 68 } |
| 69 #if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) &
& !_HAS_EXCEPTIONS) |
| 70 if (!nh) |
| 71 return false; |
| 72 // Since exceptions are disabled, we don't really know if new_handler |
| 73 // failed. Assume it will abort if it fails. |
| 74 (*nh)(); |
| 75 return true; |
| 76 #else |
| 77 // If no new_handler is established, the allocation failed. |
| 78 if (!nh) { |
| 79 if (nothrow) |
| 80 return 0; |
| 81 throw std::bad_alloc(); |
| 82 } |
| 83 // Otherwise, try the new_handler. If it returns, retry the |
| 84 // allocation. If it throws std::bad_alloc, fail the allocation. |
| 85 // if it throws something else, don't interfere. |
| 86 try { |
| 87 (*nh)(); |
| 88 } catch (const std::bad_alloc&) { |
| 89 if (!nothrow) |
| 90 throw; |
| 91 return p; |
| 92 } |
| 93 #endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPT
IONS) && !_HAS_EXCEPTIONS) |
| 94 } |
| 95 |
| 96 void* malloc(size_t size) __THROW { |
| 97 void* ptr; |
| 98 for (;;) { |
| 99 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 100 switch (allocator) { |
| 101 case JEMALLOC: |
| 102 ptr = je_malloc(size); |
| 103 break; |
| 104 case WINDEFAULT: |
| 105 case WINLFH: |
| 106 ptr = win_heap_malloc(size); |
| 107 break; |
| 108 case TCMALLOC: |
| 109 default: |
| 110 ptr = do_malloc(size); |
| 111 break; |
| 112 } |
| 113 #else |
| 114 // TCMalloc case. |
| 115 ptr = do_malloc(size); |
| 116 #endif |
| 117 if (ptr) |
| 118 return ptr; |
| 119 |
| 120 if (!new_mode || !call_new_handler(true)) |
| 121 break; |
| 122 } |
| 123 return ptr; |
| 124 } |
| 125 |
| 126 void free(void* p) __THROW { |
| 127 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 128 switch (allocator) { |
| 129 case JEMALLOC: |
| 130 je_free(p); |
| 131 return; |
| 132 case WINDEFAULT: |
| 133 case WINLFH: |
| 134 win_heap_free(p); |
| 135 return; |
| 136 } |
| 137 #endif |
| 138 // TCMalloc case. |
| 139 do_free(p); |
| 140 } |
| 141 |
| 142 void* realloc(void* ptr, size_t size) __THROW { |
| 143 void* new_ptr; |
| 144 for (;;) { |
| 145 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 146 switch (allocator) { |
| 147 case JEMALLOC: |
| 148 new_ptr = je_realloc(ptr, size); |
| 149 break; |
| 150 case WINDEFAULT: |
| 151 case WINLFH: |
| 152 new_ptr = win_heap_realloc(ptr, size); |
| 153 break; |
| 154 case TCMALLOC: |
| 155 default: |
| 156 new_ptr = do_realloc(ptr, size); |
| 157 break; |
| 158 } |
| 159 #else |
| 160 // TCMalloc case. |
| 161 new_ptr = do_realloc(ptr, size); |
| 162 #endif |
| 163 if (new_ptr) |
| 164 return new_ptr; |
| 165 if (!new_mode || !call_new_handler(true)) |
| 166 break; |
| 167 } |
| 168 return new_ptr; |
| 169 } |
| 170 |
| 171 // TODO(mbelshe): Implement this for other allocators. |
| 172 void malloc_stats(void) __THROW { |
| 173 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 174 switch (allocator) { |
| 175 case JEMALLOC: |
| 176 // No stats. |
| 177 return; |
| 178 case WINDEFAULT: |
| 179 case WINLFH: |
| 180 // No stats. |
| 181 return; |
| 182 } |
| 183 #endif |
| 184 tc_malloc_stats(); |
| 185 } |
| 186 |
| 187 #ifdef WIN32 |
| 188 |
| 189 extern "C" size_t _msize(void* p) { |
| 190 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 191 switch (allocator) { |
| 192 case JEMALLOC: |
| 193 return je_msize(p); |
| 194 case WINDEFAULT: |
| 195 case WINLFH: |
| 196 return win_heap_msize(p); |
| 197 } |
| 198 #endif |
| 199 return MallocExtension::instance()->GetAllocatedSize(p); |
| 200 } |
| 201 |
| 202 // This is included to resolve references from libcmt. |
| 203 extern "C" intptr_t _get_heap_handle() { |
| 204 return 0; |
| 205 } |
| 206 |
| 207 // The CRT heap initialization stub. |
| 208 extern "C" int _heap_init() { |
| 209 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 210 const char* override = GetenvBeforeMain("CHROME_ALLOCATOR"); |
| 211 if (override) { |
| 212 if (!stricmp(override, "jemalloc")) |
| 213 allocator = JEMALLOC; |
| 214 else if (!stricmp(override, "winheap")) |
| 215 allocator = WINDEFAULT; |
| 216 else if (!stricmp(override, "winlfh")) |
| 217 allocator = WINLFH; |
| 218 else if (!stricmp(override, "tcmalloc")) |
| 219 allocator = TCMALLOC; |
| 220 } |
| 221 |
| 222 switch (allocator) { |
| 223 case JEMALLOC: |
| 224 return je_malloc_init_hard() ? 0 : 1; |
| 225 case WINDEFAULT: |
| 226 return win_heap_init(false) ? 1 : 0; |
| 227 case WINLFH: |
| 228 return win_heap_init(true) ? 1 : 0; |
| 229 case TCMALLOC: |
| 230 default: |
| 231 // fall through |
| 232 break; |
| 233 } |
| 234 #endif |
| 235 // Initializing tcmalloc. |
| 236 // We intentionally leak this object. It lasts for the process |
| 237 // lifetime. Trying to teardown at _heap_term() is so late that |
| 238 // you can't do anything useful anyway. |
| 239 new TCMallocGuard(); |
| 240 return 1; |
| 241 } |
| 242 |
| 243 // The CRT heap cleanup stub. |
| 244 extern "C" void _heap_term() {} |
| 245 |
| 246 // We set this to 1 because part of the CRT uses a check of _crtheap != 0 |
| 247 // to test whether the CRT has been initialized. Once we've ripped out |
| 248 // the allocators from libcmt, we need to provide this definition so that |
| 249 // the rest of the CRT is still usable. |
| 250 extern "C" void* _crtheap = reinterpret_cast<void*>(1); |
| 251 |
| 252 #endif // WIN32 |
| 253 |
| 254 #include "generic_allocators.cc" |
| 255 |
| 256 } // extern C |
OLD | NEW |