OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
107 PartitionRootBase::gInitialized = true; | 107 PartitionRootBase::gInitialized = true; |
108 // We mark the seed page as free to make sure it is skipped by our | 108 // We mark the seed page as free to make sure it is skipped by our |
109 // logic to find a new active page. | 109 // logic to find a new active page. |
110 PartitionRootBase::gPagedBucket.activePagesHead = &PartitionRootGeneric: :gSeedPage; | 110 PartitionRootBase::gPagedBucket.activePagesHead = &PartitionRootGeneric: :gSeedPage; |
111 } | 111 } |
112 spinLockUnlock(&PartitionRootBase::gInitializedLock); | 112 spinLockUnlock(&PartitionRootBase::gInitializedLock); |
113 | 113 |
114 root->initialized = true; | 114 root->initialized = true; |
115 root->totalSizeOfCommittedPages = 0; | 115 root->totalSizeOfCommittedPages = 0; |
116 root->totalSizeOfSuperPages = 0; | 116 root->totalSizeOfSuperPages = 0; |
117 root->totalSizeOfDirectMappedPages = 0; | |
117 root->nextSuperPage = 0; | 118 root->nextSuperPage = 0; |
118 root->nextPartitionPage = 0; | 119 root->nextPartitionPage = 0; |
119 root->nextPartitionPageEnd = 0; | 120 root->nextPartitionPageEnd = 0; |
120 root->firstExtent = 0; | 121 root->firstExtent = 0; |
121 root->currentExtent = 0; | 122 root->currentExtent = 0; |
122 | 123 |
123 memset(&root->globalEmptyPageRing, '\0', sizeof(root->globalEmptyPageRing)); | 124 memset(&root->globalEmptyPageRing, '\0', sizeof(root->globalEmptyPageRing)); |
124 root->globalEmptyPageRingIndex = 0; | 125 root->globalEmptyPageRingIndex = 0; |
125 | 126 |
126 // This is a "magic" value so we can test if a root pointer is valid. | 127 // This is a "magic" value so we can test if a root pointer is valid. |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
289 size_t i; | 290 size_t i; |
290 for (i = 0; i < kGenericNumBucketedOrders * kGenericNumBucketsPerOrder; ++i) { | 291 for (i = 0; i < kGenericNumBucketedOrders * kGenericNumBucketsPerOrder; ++i) { |
291 PartitionBucket* bucket = &root->buckets[i]; | 292 PartitionBucket* bucket = &root->buckets[i]; |
292 if (!partitionAllocShutdownBucket(bucket)) | 293 if (!partitionAllocShutdownBucket(bucket)) |
293 noLeaks = false; | 294 noLeaks = false; |
294 } | 295 } |
295 partitionAllocBaseShutdown(root); | 296 partitionAllocBaseShutdown(root); |
296 return noLeaks; | 297 return noLeaks; |
297 } | 298 } |
298 | 299 |
299 static NEVER_INLINE void partitionOutOfMemory() | 300 |
Chris Evans
2014/11/08 07:04:43
Nit: Remove extra newline?
hiroshige
2014/11/11 09:41:30
Done.
| |
301 static NEVER_INLINE void partitionOutOfMemoryWithLotsOfUncommitedPages() | |
300 { | 302 { |
303 // Crash at a special address (0x9b) | |
304 // to be easily distinguished on crash reports. | |
305 IMMEDIATE_CRASH_WITH_FLAG(0x9b); | |
Chris Evans
2014/11/08 07:04:43
Do we think this strange quirk of Windows (missing
hiroshige
2014/11/11 09:41:30
Done.
I withdraw the macro because I feel its curr
| |
306 } | |
307 | |
308 static NEVER_INLINE void partitionOutOfMemory(const PartitionRootBase* root) | |
309 { | |
310 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
Chris Evans
2014/11/08 07:04:44
Nit: for clarity, maybe we only need to ASSERT() d
hiroshige
2014/11/11 09:41:30
Done.
| |
311 if (root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages - root- >totalSizeOfCommittedPages > kReasonableSizeOfUnusedPages) { | |
Chris Evans
2014/11/08 07:04:44
I still don't think this test has much value in 64
hiroshige
2014/11/11 09:41:30
OK, I added #if CPU(32_BIT) to limit this to 32-bi
| |
312 // OOMs where a lot of super pages are allocated but not committed, | |
313 // probably due to http://crbug.com/421387. | |
314 partitionOutOfMemoryWithLotsOfUncommitedPages(); | |
315 } | |
316 // Ordinary OOMs (where super pages are consumed and mostly committed). | |
301 IMMEDIATE_CRASH(); | 317 IMMEDIATE_CRASH(); |
302 } | 318 } |
303 | 319 |
304 static ALWAYS_INLINE void partitionDecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) | 320 static ALWAYS_INLINE void partitionDecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) |
305 { | 321 { |
306 decommitSystemPages(addr, len); | 322 decommitSystemPages(addr, len); |
307 ASSERT(root->totalSizeOfCommittedPages > len); | 323 ASSERT(root->totalSizeOfCommittedPages >= len); |
308 root->totalSizeOfCommittedPages -= len; | 324 root->totalSizeOfCommittedPages -= len; |
309 } | 325 } |
310 | 326 |
311 static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) | 327 static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) |
312 { | 328 { |
313 recommitSystemPages(addr, len); | 329 recommitSystemPages(addr, len); |
314 root->totalSizeOfCommittedPages += len; | 330 root->totalSizeOfCommittedPages += len; |
331 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
315 } | 332 } |
316 | 333 |
317 static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, int flags, uint16_t numPartitionPages) | 334 static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, int flags, uint16_t numPartitionPages) |
318 { | 335 { |
319 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPage) % kPartitionPa geSize)); | 336 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPage) % kPartitionPa geSize)); |
320 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPageEnd) % kPartitio nPageSize)); | 337 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPageEnd) % kPartitio nPageSize)); |
321 RELEASE_ASSERT(numPartitionPages <= kNumPartitionPagesPerSuperPage); | 338 RELEASE_ASSERT(numPartitionPages <= kNumPartitionPagesPerSuperPage); |
322 size_t totalSize = kPartitionPageSize * numPartitionPages; | 339 size_t totalSize = kPartitionPageSize * numPartitionPages; |
323 root->totalSizeOfCommittedPages += totalSize; | |
Chris Evans
2014/11/08 07:07:15
Whoa, the changes in this file look like an import
hiroshige
2014/11/11 09:41:30
Done.
| |
324 size_t numPartitionPagesLeft = (root->nextPartitionPageEnd - root->nextParti tionPage) >> kPartitionPageShift; | 340 size_t numPartitionPagesLeft = (root->nextPartitionPageEnd - root->nextParti tionPage) >> kPartitionPageShift; |
325 if (LIKELY(numPartitionPagesLeft >= numPartitionPages)) { | 341 if (LIKELY(numPartitionPagesLeft >= numPartitionPages)) { |
326 // In this case, we can still hand out pages from the current super page | 342 // In this case, we can still hand out pages from the current super page |
327 // allocation. | 343 // allocation. |
328 char* ret = root->nextPartitionPage; | 344 char* ret = root->nextPartitionPage; |
329 root->nextPartitionPage += totalSize; | 345 root->nextPartitionPage += totalSize; |
346 root->totalSizeOfCommittedPages += totalSize; | |
347 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages); | |
330 return ret; | 348 return ret; |
331 } | 349 } |
332 | 350 |
333 // Need a new super page. | 351 // Need a new super page. |
334 root->totalSizeOfSuperPages += kSuperPageSize; | |
335 char* requestedAddress = root->nextSuperPage; | 352 char* requestedAddress = root->nextSuperPage; |
336 char* superPage = reinterpret_cast<char*>(allocPages(requestedAddress, kSupe rPageSize, kSuperPageSize)); | 353 char* superPage = reinterpret_cast<char*>(allocPages(requestedAddress, kSupe rPageSize, kSuperPageSize)); |
337 if (UNLIKELY(!superPage)) | 354 if (UNLIKELY(!superPage)) |
338 return 0; | 355 return 0; |
356 | |
357 root->totalSizeOfSuperPages += kSuperPageSize; | |
358 root->totalSizeOfCommittedPages += totalSize; | |
359 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
360 | |
339 root->nextSuperPage = superPage + kSuperPageSize; | 361 root->nextSuperPage = superPage + kSuperPageSize; |
340 char* ret = superPage + kPartitionPageSize; | 362 char* ret = superPage + kPartitionPageSize; |
341 root->nextPartitionPage = ret + totalSize; | 363 root->nextPartitionPage = ret + totalSize; |
342 root->nextPartitionPageEnd = root->nextSuperPage - kPartitionPageSize; | 364 root->nextPartitionPageEnd = root->nextSuperPage - kPartitionPageSize; |
343 // Make the first partition page in the super page a guard page, but leave a | 365 // Make the first partition page in the super page a guard page, but leave a |
344 // hole in the middle. | 366 // hole in the middle. |
345 // This is where we put page metadata and also a tiny amount of extent | 367 // This is where we put page metadata and also a tiny amount of extent |
346 // metadata. | 368 // metadata. |
347 setSystemPagesInaccessible(superPage, kSystemPageSize); | 369 setSystemPagesInaccessible(superPage, kSystemPageSize); |
348 setSystemPagesInaccessible(superPage + (kSystemPageSize * 2), kPartitionPage Size - (kSystemPageSize * 2)); | 370 setSystemPagesInaccessible(superPage + (kSystemPageSize * 2), kPartitionPage Size - (kSystemPageSize * 2)); |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
558 // a bunch of system pages more than "size": | 580 // a bunch of system pages more than "size": |
559 // - The first few system pages are the partition page in which the super | 581 // - The first few system pages are the partition page in which the super |
560 // page metadata is stored. We fault just one system page out of a partition | 582 // page metadata is stored. We fault just one system page out of a partition |
561 // page sized clump. | 583 // page sized clump. |
562 // - We add a trailing guard page. | 584 // - We add a trailing guard page. |
563 size_t mapSize = size + kPartitionPageSize + kSystemPageSize; | 585 size_t mapSize = size + kPartitionPageSize + kSystemPageSize; |
564 // Round up to the allocation granularity. | 586 // Round up to the allocation granularity. |
565 mapSize += kPageAllocationGranularityOffsetMask; | 587 mapSize += kPageAllocationGranularityOffsetMask; |
566 mapSize &= kPageAllocationGranularityBaseMask; | 588 mapSize &= kPageAllocationGranularityBaseMask; |
567 | 589 |
568 root->totalSizeOfCommittedPages += size + kSystemPageSize; | 590 root->totalSizeOfCommittedPages += size + kSystemPageSize; |
Chris Evans
2014/11/08 07:04:44
Nit: calculate "size + kSystemPageSize" into a sep
hiroshige
2014/11/11 09:41:30
Done.
| |
591 root->totalSizeOfDirectMappedPages += size + kSystemPageSize; | |
592 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
569 | 593 |
570 // TODO: we may want to let the operating system place these allocations | 594 // TODO: we may want to let the operating system place these allocations |
571 // where it pleases. On 32-bit, this might limit address space | 595 // where it pleases. On 32-bit, this might limit address space |
572 // fragmentation and on 64-bit, this might have useful savings for TLB | 596 // fragmentation and on 64-bit, this might have useful savings for TLB |
573 // and page table overhead. | 597 // and page table overhead. |
574 // TODO: if upsizing realloc()s are common on large sizes, we could | 598 // TODO: if upsizing realloc()s are common on large sizes, we could |
575 // consider over-allocating address space on 64-bit, "just in case". | 599 // consider over-allocating address space on 64-bit, "just in case". |
576 // TODO: consider pre-populating page tables (e.g. MAP_POPULATE on Linux, | 600 // TODO: consider pre-populating page tables (e.g. MAP_POPULATE on Linux, |
577 // MADV_WILLNEED on POSIX). | 601 // MADV_WILLNEED on POSIX). |
578 // TODO: these pages will be zero-filled. Consider internalizing an | 602 // TODO: these pages will be zero-filled. Consider internalizing an |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
613 } | 637 } |
614 | 638 |
615 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) | 639 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) |
616 { | 640 { |
617 size_t unmapSize = partitionPageToDirectMapExtent(page)->mapSize; | 641 size_t unmapSize = partitionPageToDirectMapExtent(page)->mapSize; |
618 | 642 |
619 // Add on the size of the trailing guard page and preceeding partition | 643 // Add on the size of the trailing guard page and preceeding partition |
620 // page. | 644 // page. |
621 unmapSize += kPartitionPageSize + kSystemPageSize; | 645 unmapSize += kPartitionPageSize + kSystemPageSize; |
622 | 646 |
623 PartitionRootBase* root = partitionPageToRoot(page); | 647 PartitionRootBase* root = partitionPageToRoot(page); |
Chris Evans
2014/11/08 07:04:44
Nit: calculate "page->bucket->slotSize + kSystemPa
hiroshige
2014/11/11 09:41:29
Done.
| |
648 ASSERT(root->totalSizeOfCommittedPages >= page->bucket->slotSize + kSystemPa geSize); | |
624 root->totalSizeOfCommittedPages -= page->bucket->slotSize + kSystemPageSize; | 649 root->totalSizeOfCommittedPages -= page->bucket->slotSize + kSystemPageSize; |
650 ASSERT(root->totalSizeOfDirectMappedPages >= page->bucket->slotSize + kSyste mPageSize); | |
651 root->totalSizeOfDirectMappedPages -= page->bucket->slotSize + kSystemPageSi ze; | |
625 | 652 |
626 ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask)); | 653 ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask)); |
627 | 654 |
628 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); | 655 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); |
629 // Account for the mapping starting a partition page before the actual | 656 // Account for the mapping starting a partition page before the actual |
630 // allocation address. | 657 // allocation address. |
631 ptr -= kPartitionPageSize; | 658 ptr -= kPartitionPageSize; |
632 | 659 |
633 freePages(ptr, unmapSize); | 660 freePages(ptr, unmapSize); |
634 } | 661 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
694 newPage = partitionPointerToPageNoAlignmentCheck(rawNewPage); | 721 newPage = partitionPointerToPageNoAlignmentCheck(rawNewPage); |
695 } | 722 } |
696 | 723 |
697 partitionPageReset(newPage, bucket); | 724 partitionPageReset(newPage, bucket); |
698 bucket->activePagesHead = newPage; | 725 bucket->activePagesHead = newPage; |
699 return partitionPageAllocAndFillFreelist(newPage); | 726 return partitionPageAllocAndFillFreelist(newPage); |
700 | 727 |
701 partitionAllocSlowPathFailed: | 728 partitionAllocSlowPathFailed: |
702 if (returnNull) | 729 if (returnNull) |
703 return nullptr; | 730 return nullptr; |
704 partitionOutOfMemory(); | 731 partitionOutOfMemory(root); |
705 return nullptr; | 732 return nullptr; |
706 } | 733 } |
707 | 734 |
708 static ALWAYS_INLINE void partitionFreePage(PartitionRootBase* root, PartitionPa ge* page) | 735 static ALWAYS_INLINE void partitionFreePage(PartitionRootBase* root, PartitionPa ge* page) |
709 { | 736 { |
710 ASSERT(page->freelistHead); | 737 ASSERT(page->freelistHead); |
711 ASSERT(!page->numAllocatedSlots); | 738 ASSERT(!page->numAllocatedSlots); |
712 partitionUnusePage(root, page); | 739 partitionUnusePage(root, page); |
713 // We actually leave the freed page in the active list. We'll sweep it on | 740 // We actually leave the freed page in the active list. We'll sweep it on |
714 // to the free page list when we next walk the active page list. Pulling | 741 // to the free page list when we next walk the active page list. Pulling |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
973 printf("total live: %zu bytes\n", totalLive); | 1000 printf("total live: %zu bytes\n", totalLive); |
974 printf("total resident: %zu bytes\n", totalResident); | 1001 printf("total resident: %zu bytes\n", totalResident); |
975 printf("total freeable: %zu bytes\n", totalFreeable); | 1002 printf("total freeable: %zu bytes\n", totalFreeable); |
976 fflush(stdout); | 1003 fflush(stdout); |
977 } | 1004 } |
978 | 1005 |
979 #endif // !NDEBUG | 1006 #endif // !NDEBUG |
980 | 1007 |
981 } // namespace WTF | 1008 } // namespace WTF |
982 | 1009 |
OLD | NEW |