| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/allocator/allocator_shim.h" |
| 6 |
| 5 #include <config.h> | 7 #include <config.h> |
| 6 | 8 |
| 7 // When defined, different heap allocators can be used via an environment | 9 // When defined, different heap allocators can be used via an environment |
| 8 // variable set before running the program. This may reduce the amount | 10 // variable set before running the program. This may reduce the amount |
| 9 // of inlining that we get with malloc/free/etc. Disabling makes it | 11 // of inlining that we get with malloc/free/etc. Disabling makes it |
| 10 // so that only tcmalloc can be used. | 12 // so that only tcmalloc can be used. |
| 11 #define ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 13 #define ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 12 | 14 |
| 13 // TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth | 15 // 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. | 16 // from the "user code" so that debugging tools (HeapChecker) can work. |
| 15 | 17 |
| 16 // __THROW is defined in glibc systems. It means, counter-intuitively, | 18 // __THROW is defined in glibc systems. It means, counter-intuitively, |
| 17 // "This function will never throw an exception." It's an optional | 19 // "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. | 20 // 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 | 21 #ifndef __THROW // I guess we're not on a glibc system |
| 20 # define __THROW // __THROW is just an optimization, so ok to make it "" | 22 # define __THROW // __THROW is just an optimization, so ok to make it "" |
| 21 #endif | 23 #endif |
| 22 | 24 |
| 23 // new_mode behaves similarly to MSVC's _set_new_mode. | 25 // new_mode behaves similarly to MSVC's _set_new_mode. |
| 24 // If flag is 0 (default), calls to malloc will behave normally. | 26 // 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, | 27 // If flag is 1, calls to malloc will behave like calls to new, |
| 26 // and the std_new_handler will be invoked on failure. | 28 // and the std_new_handler will be invoked on failure. |
| 27 // Can be set by calling _set_new_mode(). | 29 // Can be set by calling _set_new_mode(). |
| 28 static int new_mode = 0; | 30 static int new_mode = 0; |
| 29 | 31 |
| 30 typedef enum { | 32 typedef enum { |
| 31 TCMALLOC, // TCMalloc is the default allocator. | 33 TCMALLOC, // TCMalloc is the default allocator. |
| 32 JEMALLOC, // JEMalloc | 34 JEMALLOC, // JEMalloc. |
| 33 WINDEFAULT, // Windows Heap | 35 WINHEAP, // Windows Heap (standard Windows allocator). |
| 34 WINLFH, // Windows LFH Heap | 36 WINLFH, // Windows LFH Heap. |
| 35 } Allocator; | 37 } Allocator; |
| 36 | 38 |
| 37 // This is the default allocator. | 39 // This is the default allocator. This value can be changed at startup by |
| 38 static Allocator allocator = TCMALLOC; | 40 // specifying environment variables shown below it. |
| 41 // See SetupSubprocessAllocator() to specify a default secondary (subprocess) |
| 42 // allocator. |
| 43 // TODO(jar): Switch to using TCMALLOC for the renderer as well. |
| 44 static Allocator allocator = WINHEAP; |
| 45 |
| 46 // The names of the environment variables that can optionally control the |
| 47 // selection of the allocator. The primary may be used to control overall |
| 48 // allocator selection, and the secondary can be used to specify an allocator |
| 49 // to use in sub-processes. |
| 50 static const char* primary_name = "CHROME_ALLOCATOR"; |
| 51 static const char* secondary_name = "CHROME_ALLOCATOR_2"; |
| 39 | 52 |
| 40 // We include tcmalloc and the win_allocator to get as much inlining as | 53 // We include tcmalloc and the win_allocator to get as much inlining as |
| 41 // possible. | 54 // possible. |
| 42 #include "tcmalloc.cc" | 55 #include "tcmalloc.cc" |
| 43 #include "win_allocator.cc" | 56 #include "win_allocator.cc" |
| 44 | 57 |
| 45 // Forward declarations from jemalloc. | 58 // Forward declarations from jemalloc. |
| 46 extern "C" { | 59 extern "C" { |
| 47 void* je_malloc(size_t s); | 60 void* je_malloc(size_t s); |
| 48 void* je_realloc(void* p, size_t s); | 61 void* je_realloc(void* p, size_t s); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 } | 107 } |
| 95 | 108 |
| 96 void* malloc(size_t size) __THROW { | 109 void* malloc(size_t size) __THROW { |
| 97 void* ptr; | 110 void* ptr; |
| 98 for (;;) { | 111 for (;;) { |
| 99 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 112 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 100 switch (allocator) { | 113 switch (allocator) { |
| 101 case JEMALLOC: | 114 case JEMALLOC: |
| 102 ptr = je_malloc(size); | 115 ptr = je_malloc(size); |
| 103 break; | 116 break; |
| 104 case WINDEFAULT: | 117 case WINHEAP: |
| 105 case WINLFH: | 118 case WINLFH: |
| 106 ptr = win_heap_malloc(size); | 119 ptr = win_heap_malloc(size); |
| 107 break; | 120 break; |
| 108 case TCMALLOC: | 121 case TCMALLOC: |
| 109 default: | 122 default: |
| 110 ptr = do_malloc(size); | 123 ptr = do_malloc(size); |
| 111 break; | 124 break; |
| 112 } | 125 } |
| 113 #else | 126 #else |
| 114 // TCMalloc case. | 127 // TCMalloc case. |
| 115 ptr = do_malloc(size); | 128 ptr = do_malloc(size); |
| 116 #endif | 129 #endif |
| 117 if (ptr) | 130 if (ptr) |
| 118 return ptr; | 131 return ptr; |
| 119 | 132 |
| 120 if (!new_mode || !call_new_handler(true)) | 133 if (!new_mode || !call_new_handler(true)) |
| 121 break; | 134 break; |
| 122 } | 135 } |
| 123 return ptr; | 136 return ptr; |
| 124 } | 137 } |
| 125 | 138 |
| 126 void free(void* p) __THROW { | 139 void free(void* p) __THROW { |
| 127 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 140 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 128 switch (allocator) { | 141 switch (allocator) { |
| 129 case JEMALLOC: | 142 case JEMALLOC: |
| 130 je_free(p); | 143 je_free(p); |
| 131 return; | 144 return; |
| 132 case WINDEFAULT: | 145 case WINHEAP: |
| 133 case WINLFH: | 146 case WINLFH: |
| 134 win_heap_free(p); | 147 win_heap_free(p); |
| 135 return; | 148 return; |
| 136 } | 149 } |
| 137 #endif | 150 #endif |
| 138 // TCMalloc case. | 151 // TCMalloc case. |
| 139 do_free(p); | 152 do_free(p); |
| 140 } | 153 } |
| 141 | 154 |
| 142 void* realloc(void* ptr, size_t size) __THROW { | 155 void* realloc(void* ptr, size_t size) __THROW { |
| 143 // Webkit is brittle for allocators that return NULL for malloc(0). The | 156 // Webkit is brittle for allocators that return NULL for malloc(0). The |
| 144 // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure | 157 // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure |
| 145 // to call malloc for this case. | 158 // to call malloc for this case. |
| 146 if (!ptr) | 159 if (!ptr) |
| 147 return malloc(size); | 160 return malloc(size); |
| 148 | 161 |
| 149 void* new_ptr; | 162 void* new_ptr; |
| 150 for (;;) { | 163 for (;;) { |
| 151 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 164 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 152 switch (allocator) { | 165 switch (allocator) { |
| 153 case JEMALLOC: | 166 case JEMALLOC: |
| 154 new_ptr = je_realloc(ptr, size); | 167 new_ptr = je_realloc(ptr, size); |
| 155 break; | 168 break; |
| 156 case WINDEFAULT: | 169 case WINHEAP: |
| 157 case WINLFH: | 170 case WINLFH: |
| 158 new_ptr = win_heap_realloc(ptr, size); | 171 new_ptr = win_heap_realloc(ptr, size); |
| 159 break; | 172 break; |
| 160 case TCMALLOC: | 173 case TCMALLOC: |
| 161 default: | 174 default: |
| 162 new_ptr = do_realloc(ptr, size); | 175 new_ptr = do_realloc(ptr, size); |
| 163 break; | 176 break; |
| 164 } | 177 } |
| 165 #else | 178 #else |
| 166 // TCMalloc case. | 179 // TCMalloc case. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 178 return new_ptr; | 191 return new_ptr; |
| 179 } | 192 } |
| 180 | 193 |
| 181 // TODO(mbelshe): Implement this for other allocators. | 194 // TODO(mbelshe): Implement this for other allocators. |
| 182 void malloc_stats(void) __THROW { | 195 void malloc_stats(void) __THROW { |
| 183 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 196 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 184 switch (allocator) { | 197 switch (allocator) { |
| 185 case JEMALLOC: | 198 case JEMALLOC: |
| 186 // No stats. | 199 // No stats. |
| 187 return; | 200 return; |
| 188 case WINDEFAULT: | 201 case WINHEAP: |
| 189 case WINLFH: | 202 case WINLFH: |
| 190 // No stats. | 203 // No stats. |
| 191 return; | 204 return; |
| 192 } | 205 } |
| 193 #endif | 206 #endif |
| 194 tc_malloc_stats(); | 207 tc_malloc_stats(); |
| 195 } | 208 } |
| 196 | 209 |
| 197 #ifdef WIN32 | 210 #ifdef WIN32 |
| 198 | 211 |
| 199 extern "C" size_t _msize(void* p) { | 212 extern "C" size_t _msize(void* p) { |
| 200 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 213 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 201 switch (allocator) { | 214 switch (allocator) { |
| 202 case JEMALLOC: | 215 case JEMALLOC: |
| 203 return je_msize(p); | 216 return je_msize(p); |
| 204 case WINDEFAULT: | 217 case WINHEAP: |
| 205 case WINLFH: | 218 case WINLFH: |
| 206 return win_heap_msize(p); | 219 return win_heap_msize(p); |
| 207 } | 220 } |
| 208 #endif | 221 #endif |
| 209 return MallocExtension::instance()->GetAllocatedSize(p); | 222 return MallocExtension::instance()->GetAllocatedSize(p); |
| 210 } | 223 } |
| 211 | 224 |
| 212 // This is included to resolve references from libcmt. | 225 // This is included to resolve references from libcmt. |
| 213 extern "C" intptr_t _get_heap_handle() { | 226 extern "C" intptr_t _get_heap_handle() { |
| 214 return 0; | 227 return 0; |
| 215 } | 228 } |
| 216 | 229 |
| 217 // The CRT heap initialization stub. | 230 // The CRT heap initialization stub. |
| 218 extern "C" int _heap_init() { | 231 extern "C" int _heap_init() { |
| 219 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING | 232 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 220 const char* override = GetenvBeforeMain("CHROME_ALLOCATOR"); | 233 const char* environment_value = GetenvBeforeMain(primary_name); |
| 221 if (override) { | 234 if (environment_value) { |
| 222 if (!stricmp(override, "jemalloc")) | 235 if (!stricmp(environment_value, "jemalloc")) |
| 223 allocator = JEMALLOC; | 236 allocator = JEMALLOC; |
| 224 else if (!stricmp(override, "winheap")) | 237 else if (!stricmp(environment_value, "winheap")) |
| 225 allocator = WINDEFAULT; | 238 allocator = WINHEAP; |
| 226 else if (!stricmp(override, "winlfh")) | 239 else if (!stricmp(environment_value, "winlfh")) |
| 227 allocator = WINLFH; | 240 allocator = WINLFH; |
| 228 else if (!stricmp(override, "tcmalloc")) | 241 else if (!stricmp(environment_value, "tcmalloc")) |
| 229 allocator = TCMALLOC; | 242 allocator = TCMALLOC; |
| 230 } | 243 } |
| 231 | 244 |
| 232 switch (allocator) { | 245 switch (allocator) { |
| 233 case JEMALLOC: | 246 case JEMALLOC: |
| 234 return je_malloc_init_hard() ? 0 : 1; | 247 return je_malloc_init_hard() ? 0 : 1; |
| 235 case WINDEFAULT: | 248 case WINHEAP: |
| 236 return win_heap_init(false) ? 1 : 0; | 249 return win_heap_init(false) ? 1 : 0; |
| 237 case WINLFH: | 250 case WINLFH: |
| 238 return win_heap_init(true) ? 1 : 0; | 251 return win_heap_init(true) ? 1 : 0; |
| 239 case TCMALLOC: | 252 case TCMALLOC: |
| 240 default: | 253 default: |
| 241 // fall through | 254 // fall through |
| 242 break; | 255 break; |
| 243 } | 256 } |
| 244 #endif | 257 #endif |
| 245 // Initializing tcmalloc. | 258 // Initializing tcmalloc. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 257 // to test whether the CRT has been initialized. Once we've ripped out | 270 // to test whether the CRT has been initialized. Once we've ripped out |
| 258 // the allocators from libcmt, we need to provide this definition so that | 271 // the allocators from libcmt, we need to provide this definition so that |
| 259 // the rest of the CRT is still usable. | 272 // the rest of the CRT is still usable. |
| 260 extern "C" void* _crtheap = reinterpret_cast<void*>(1); | 273 extern "C" void* _crtheap = reinterpret_cast<void*>(1); |
| 261 | 274 |
| 262 #endif // WIN32 | 275 #endif // WIN32 |
| 263 | 276 |
| 264 #include "generic_allocators.cc" | 277 #include "generic_allocators.cc" |
| 265 | 278 |
| 266 } // extern C | 279 } // extern C |
| 280 |
| 281 namespace base { |
| 282 namespace allocator { |
| 283 |
| 284 void SetupSubprocessAllocator() { |
| 285 #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 286 size_t primary_length = 0; |
| 287 getenv_s(&primary_length, NULL, 0, primary_name); |
| 288 |
| 289 size_t secondary_length = 0; |
| 290 char buffer[20]; |
| 291 getenv_s(&secondary_length, buffer, sizeof(buffer), secondary_name); |
| 292 DCHECK_GT(sizeof(buffer), secondary_length); |
| 293 buffer[sizeof(buffer) - 1] = '\0'; |
| 294 |
| 295 if (secondary_length || !primary_length) { |
| 296 char* secondary_value = secondary_length ? buffer : "TCMALLOC"; |
| 297 // Force renderer (or other subprocesses) to use secondary_value. |
| 298 int ret_val = _putenv_s(primary_name, secondary_value); |
| 299 CHECK_EQ(0, ret_val); |
| 300 } |
| 301 #endif // ENABLE_DYNAMIC_ALLOCATOR_SWITCHING |
| 302 } |
| 303 |
| 304 } // namespace base. |
| 305 } // namespace allocator. |
| OLD | NEW |