Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / third_party / tcmalloc / chromium / src / pagemap.h
blob018619740e83bfffc94ff64e6f71be7062b7edc1
1 // Copyright (c) 2005, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 // ---
31 // Author: Sanjay Ghemawat <opensource@google.com>
33 // A data structure used by the caching malloc. It maps from page# to
34 // a pointer that contains info about that page. We use two
35 // representations: one for 32-bit addresses, and another for 64 bit
36 // addresses. Both representations provide the same interface. The
37 // first representation is implemented as a flat array, the seconds as
38 // a three-level radix tree that strips away approximately 1/3rd of
39 // the bits every time.
41 // The BITS parameter should be the number of bits required to hold
42 // a page number. E.g., with 32 bit pointers and 4K pages (i.e.,
43 // page offset fits in lower 12 bits), BITS == 20.
45 #ifndef TCMALLOC_PAGEMAP_H_
46 #define TCMALLOC_PAGEMAP_H_
48 #include "config.h"
50 #include <stddef.h> // for NULL, size_t
51 #include <string.h> // for memset
52 #if defined HAVE_STDINT_H
53 #include <stdint.h>
54 #elif defined HAVE_INTTYPES_H
55 #include <inttypes.h>
56 #else
57 #include <sys/types.h>
58 #endif
59 #ifdef WIN32
60 // TODO(jar): This is not needed when TCMalloc_PageMap1_LazyCommit has an API
61 // supporting commit and reservation of memory.
62 #include "common.h"
63 #endif
65 #include "internal_logging.h" // for ASSERT
67 // Single-level array
68 template <int BITS>
69 class TCMalloc_PageMap1 {
70 private:
71 static const int LENGTH = 1 << BITS;
73 void** array_;
75 public:
76 typedef uintptr_t Number;
78 explicit TCMalloc_PageMap1(void* (*allocator)(size_t)) {
79 array_ = reinterpret_cast<void**>((*allocator)(sizeof(void*) << BITS));
80 memset(array_, 0, sizeof(void*) << BITS);
83 // Ensure that the map contains initialized entries "x .. x+n-1".
84 // Returns true if successful, false if we could not allocate memory.
85 bool Ensure(Number x, size_t n) {
86 // Nothing to do since flat array was allocated at start. All
87 // that's left is to check for overflow (that is, we don't want to
88 // ensure a number y where array_[y] would be an out-of-bounds
89 // access).
90 return n <= LENGTH - x; // an overflow-free way to do "x + n <= LENGTH"
93 void PreallocateMoreMemory() {}
95 // Return the current value for KEY. Returns NULL if not yet set,
96 // or if k is out of range.
97 void* get(Number k) const {
98 if ((k >> BITS) > 0) {
99 return NULL;
101 return array_[k];
104 // REQUIRES "k" is in range "[0,2^BITS-1]".
105 // REQUIRES "k" has been ensured before.
107 // Sets the value 'v' for key 'k'.
108 void set(Number k, void* v) {
109 array_[k] = v;
112 // Return the first non-NULL pointer found in this map for
113 // a page number >= k. Returns NULL if no such number is found.
114 void* Next(Number k) const {
115 while (k < (1 << BITS)) {
116 if (array_[k] != NULL) return array_[k];
117 k++;
119 return NULL;
123 #ifdef WIN32
124 // Lazy commit, single-level array.
125 // Very similar to PageMap1, except the page map is only committed as needed.
126 // Since we don't return memory to the OS, the committed portion of the map will
127 // only grow, and we'll only be called to Ensure when we really grow the heap.
128 // We maintain a bit map to help us deduce if we've already committed a range
129 // in our map.
130 template <int BITS>
131 class TCMalloc_PageMap1_LazyCommit {
132 private:
133 // Dimension of our page map array_.
134 static const int LENGTH = 1 << BITS;
136 // The page map array that sits in reserved virtual space. Pages of this
137 // array are committed as they are needed. For each page of virtual memory,
138 // we potentially have a pointer to a span instance.
139 void** array_;
141 // A bit vector that allows us to deduce what pages in array_ are committed.
142 // Note that 2^3 = 8 bits per char, and hence the use of the magical "3" in
143 // the array range gives us the effective "divide by 8".
144 char committed_[sizeof(void*) << (BITS - kPageShift - 3)];
146 // Given an |index| into |array_|, find the page number in |array_| that holds
147 // that element.
148 size_t ContainingPage(size_t index) const {
149 return (index * sizeof(*array_)) >> kPageShift;
152 // Find out if the given page_num index in array_ is in committed memory.
153 bool IsCommitted(size_t page_num) const {
154 return committed_[page_num >> 3] & (1 << (page_num & 0x7));
157 // Remember that the given page_num index in array_ is in committed memory.
158 void SetCommitted(size_t page_num) {
159 committed_[page_num >> 3] |= (1 << (page_num & 0x7));
162 public:
163 typedef uintptr_t Number;
165 explicit TCMalloc_PageMap1_LazyCommit(void* (*allocator)(size_t)) {
166 // TODO(jar): We need a reservation function, but current API to this class
167 // only provides an allocator.
168 // Get decommitted memory. We will commit as necessary.
169 size_t size = sizeof(*array_) << BITS;
170 array_ = reinterpret_cast<void**>(VirtualAlloc(
171 NULL, size, MEM_RESERVE, PAGE_READWRITE));
172 tcmalloc::update_metadata_system_bytes(size);
173 tcmalloc::update_metadata_unmapped_bytes(size);
175 // Make sure we divided LENGTH evenly.
176 ASSERT(sizeof(committed_) * 8 == (LENGTH * sizeof(*array_)) >> kPageShift);
177 // Indicate that none of the pages of array_ have been committed yet.
178 memset(committed_, 0, sizeof(committed_));
181 // Ensure that the map contains initialized and committed entries in array_ to
182 // describe pages "x .. x+n-1".
183 // Returns true if successful, false if we could not ensure this.
184 // If we have to commit more memory in array_ (which also clears said memory),
185 // then we'll set some of the bits in committed_ to remember this fact.
186 // Only the bits of committed_ near end-points for calls to Ensure() are ever
187 // set, as the calls to Ensure() will never have overlapping ranges other than
188 // at their end-points.
190 // Example: Suppose the OS allocates memory in pages including 40...50, and
191 // later the OS allocates memory in pages 51...83. When the first allocation
192 // of 40...50 is observed, then Ensure of (39,51) will be called. The range
193 // shown in the arguments is extended so that tcmalloc can look to see if
194 // adjacent pages are part of a span that can be coaleced. Later, when pages
195 // 51...83 are allocated, Ensure() will be called with arguments (50,84),
196 // broadened again for the same reason.
198 // After the above, we would NEVER get a call such as Ensure(45,60), as that
199 // overlaps with the interior of prior ensured regions. We ONLY get an Ensure
200 // call when the OS has allocated memory, and since we NEVER give memory back
201 // to the OS, the OS can't possible allocate the same region to us twice, and
202 // can't induce an Ensure() on an interior of previous Ensure call.
204 // Also note that OS allocations are NOT guaranteed to be consecutive (there
205 // may be "holes" where code etc. uses the virtual addresses), or to appear in
206 // any order, such as lowest to highest, or vice versa (as other independent
207 // allocation systems in the process may be performing VirtualAllocations and
208 // VirtualFrees asynchronously.)
209 bool Ensure(Number x, size_t n) {
210 if (n > LENGTH - x)
211 return false; // We won't Ensure mapping for last pages in memory.
212 ASSERT(n > 0);
214 // For a given page number in memory, calculate what page in array_ needs to
215 // be memory resident. Note that we really only need a few bytes in array_
216 // for each page of virtual space we have to map, but we can only commit
217 // whole pages of array_. For instance, a 4K page of array_ has about 1k
218 // entries, and hence can map about 1K pages, or a total of about 4MB
219 // typically. As a result, it is possible that the first entry in array_,
220 // and the n'th entry in array_, will sit in the same page of array_.
221 size_t first_page = ContainingPage(x);
222 size_t last_page = ContainingPage(x + n - 1);
224 // Check at each boundary, to see if we need to commit at that end. Some
225 // other neighbor may have already forced us to commit at either or both
226 // boundaries.
227 if (IsCommitted(first_page)) {
228 if (first_page == last_page) return true;
229 ++first_page;
230 if (IsCommitted(first_page)) {
231 if (first_page == last_page) return true;
232 ++first_page;
236 if (IsCommitted(last_page)) {
237 if (first_page == last_page) return true;
238 --last_page;
239 if (IsCommitted(last_page)) {
240 if (first_page == last_page) return true;
241 --last_page;
245 ASSERT(!IsCommitted(last_page));
246 ASSERT(!IsCommitted(first_page));
248 void* start = reinterpret_cast<char*>(array_) + (first_page << kPageShift);
249 size_t length = (last_page - first_page + 1) << kPageShift;
251 #ifndef NDEBUG
252 // Validate we are committing new sections, and hence we're not clearing any
253 // existing data.
254 MEMORY_BASIC_INFORMATION info = {0};
255 size_t result = VirtualQuery(start, &info, sizeof(info));
256 ASSERT(result);
257 ASSERT(0 == (info.State & MEM_COMMIT)); // It starts with uncommitted.
258 ASSERT(info.RegionSize >= length); // Entire length is uncommitted.
259 #endif
261 TCMalloc_SystemCommit(start, length);
262 tcmalloc::update_metadata_unmapped_bytes(-length);
264 #ifndef NDEBUG
265 result = VirtualQuery(start, &info, sizeof(info));
266 ASSERT(result);
267 ASSERT(0 != (info.State & MEM_COMMIT)); // Now it is committed.
268 ASSERT(info.RegionSize >= length); // Entire length is committed.
269 #endif
271 // As noted in the large comment/example describing this method, we will
272 // never be called with a range of pages very much inside this |first_page|
273 // to |last_page| range.
274 // As a result, we only need to set bits for each end of that range, and one
275 // page inside each end.
276 SetCommitted(first_page);
277 if (first_page < last_page) {
278 SetCommitted(last_page);
279 SetCommitted(first_page + 1); // These may be duplicates now.
280 SetCommitted(last_page - 1);
283 return true;
286 // This is a premature call to get all the meta-memory allocated, so as to
287 // avoid virtual space fragmentation. Since we pre-reserved all memory, we
288 // don't need to do anything here (we won't fragment virtual space).
289 void PreallocateMoreMemory() {}
291 // Return the current value for KEY. Returns NULL if not yet set,
292 // or if k is out of range.
293 void* get(Number k) const {
294 if ((k >> BITS) > 0) {
295 return NULL;
297 return array_[k];
300 // REQUIRES "k" is in range "[0,2^BITS-1]".
301 // REQUIRES "k" has been ensured before.
303 // Sets the value for KEY.
304 void set(Number k, void* v) {
305 array_[k] = v;
307 // Return the first non-NULL pointer found in this map for
308 // a page number >= k. Returns NULL if no such number is found.
309 void* Next(Number k) const {
310 while (k < (1 << BITS)) {
311 if (array_[k] != NULL) return array_[k];
312 k++;
314 return NULL;
317 #endif // WIN32
320 // Two-level radix tree
321 template <int BITS>
322 class TCMalloc_PageMap2 {
323 private:
324 // Put 32 entries in the root and (2^BITS)/32 entries in each leaf.
325 static const int ROOT_BITS = 5;
326 static const int ROOT_LENGTH = 1 << ROOT_BITS;
328 static const int LEAF_BITS = BITS - ROOT_BITS;
329 static const int LEAF_LENGTH = 1 << LEAF_BITS;
331 // Leaf node
332 struct Leaf {
333 void* values[LEAF_LENGTH];
336 Leaf* root_[ROOT_LENGTH]; // Pointers to 32 child nodes
337 void* (*allocator_)(size_t); // Memory allocator
339 public:
340 typedef uintptr_t Number;
342 explicit TCMalloc_PageMap2(void* (*allocator)(size_t)) {
343 allocator_ = allocator;
344 memset(root_, 0, sizeof(root_));
347 void* get(Number k) const {
348 const Number i1 = k >> LEAF_BITS;
349 const Number i2 = k & (LEAF_LENGTH-1);
350 if ((k >> BITS) > 0 || root_[i1] == NULL) {
351 return NULL;
353 return root_[i1]->values[i2];
356 void set(Number k, void* v) {
357 ASSERT(k >> BITS == 0);
358 const Number i1 = k >> LEAF_BITS;
359 const Number i2 = k & (LEAF_LENGTH-1);
360 root_[i1]->values[i2] = v;
363 bool Ensure(Number start, size_t n) {
364 for (Number key = start; key <= start + n - 1; ) {
365 const Number i1 = key >> LEAF_BITS;
367 // Check for overflow
368 if (i1 >= ROOT_LENGTH)
369 return false;
371 // Make 2nd level node if necessary
372 if (root_[i1] == NULL) {
373 Leaf* leaf = reinterpret_cast<Leaf*>((*allocator_)(sizeof(Leaf)));
374 if (leaf == NULL) return false;
375 memset(leaf, 0, sizeof(*leaf));
376 root_[i1] = leaf;
379 // Advance key past whatever is covered by this leaf node
380 key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
382 return true;
385 void PreallocateMoreMemory() {
386 // Allocate enough to keep track of all possible pages
387 Ensure(0, 1 << BITS);
390 void* Next(Number k) const {
391 while (k < (1 << BITS)) {
392 const Number i1 = k >> LEAF_BITS;
393 Leaf* leaf = root_[i1];
394 if (leaf != NULL) {
395 // Scan forward in leaf
396 for (Number i2 = k & (LEAF_LENGTH - 1); i2 < LEAF_LENGTH; i2++) {
397 if (leaf->values[i2] != NULL) {
398 return leaf->values[i2];
402 // Skip to next top-level entry
403 k = (i1 + 1) << LEAF_BITS;
405 return NULL;
409 // Three-level radix tree
410 template <int BITS>
411 class TCMalloc_PageMap3 {
412 private:
413 // How many bits should we consume at each interior level
414 static const int INTERIOR_BITS = (BITS + 2) / 3; // Round-up
415 static const int INTERIOR_LENGTH = 1 << INTERIOR_BITS;
417 // How many bits should we consume at leaf level
418 static const int LEAF_BITS = BITS - 2*INTERIOR_BITS;
419 static const int LEAF_LENGTH = 1 << LEAF_BITS;
421 // Interior node
422 struct Node {
423 Node* ptrs[INTERIOR_LENGTH];
426 // Leaf node
427 struct Leaf {
428 void* values[LEAF_LENGTH];
431 Node* root_; // Root of radix tree
432 void* (*allocator_)(size_t); // Memory allocator
434 Node* NewNode() {
435 Node* result = reinterpret_cast<Node*>((*allocator_)(sizeof(Node)));
436 if (result != NULL) {
437 memset(result, 0, sizeof(*result));
439 return result;
442 public:
443 typedef uintptr_t Number;
445 explicit TCMalloc_PageMap3(void* (*allocator)(size_t)) {
446 allocator_ = allocator;
447 root_ = NewNode();
450 void* get(Number k) const {
451 const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
452 const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
453 const Number i3 = k & (LEAF_LENGTH-1);
454 if ((k >> BITS) > 0 ||
455 root_->ptrs[i1] == NULL || root_->ptrs[i1]->ptrs[i2] == NULL) {
456 return NULL;
458 return reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2])->values[i3];
461 void set(Number k, void* v) {
462 ASSERT(k >> BITS == 0);
463 const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
464 const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
465 const Number i3 = k & (LEAF_LENGTH-1);
466 reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2])->values[i3] = v;
469 bool Ensure(Number start, size_t n) {
470 for (Number key = start; key <= start + n - 1; ) {
471 const Number i1 = key >> (LEAF_BITS + INTERIOR_BITS);
472 const Number i2 = (key >> LEAF_BITS) & (INTERIOR_LENGTH-1);
474 // Check for overflow
475 if (i1 >= INTERIOR_LENGTH || i2 >= INTERIOR_LENGTH)
476 return false;
478 // Make 2nd level node if necessary
479 if (root_->ptrs[i1] == NULL) {
480 Node* n = NewNode();
481 if (n == NULL) return false;
482 root_->ptrs[i1] = n;
485 // Make leaf node if necessary
486 if (root_->ptrs[i1]->ptrs[i2] == NULL) {
487 Leaf* leaf = reinterpret_cast<Leaf*>((*allocator_)(sizeof(Leaf)));
488 if (leaf == NULL) return false;
489 memset(leaf, 0, sizeof(*leaf));
490 root_->ptrs[i1]->ptrs[i2] = reinterpret_cast<Node*>(leaf);
493 // Advance key past whatever is covered by this leaf node
494 key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
496 return true;
499 void PreallocateMoreMemory() {
502 void* Next(Number k) const {
503 while (k < (Number(1) << BITS)) {
504 const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
505 const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1);
506 if (root_->ptrs[i1] == NULL) {
507 // Advance to next top-level entry
508 k = (i1 + 1) << (LEAF_BITS + INTERIOR_BITS);
509 } else {
510 Leaf* leaf = reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2]);
511 if (leaf != NULL) {
512 for (Number i3 = (k & (LEAF_LENGTH-1)); i3 < LEAF_LENGTH; i3++) {
513 if (leaf->values[i3] != NULL) {
514 return leaf->values[i3];
518 // Advance to next interior entry
519 k = ((k >> LEAF_BITS) + 1) << LEAF_BITS;
522 return NULL;
526 #endif // TCMALLOC_PAGEMAP_H_