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 |