Chromium Code Reviews| 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 |