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 #if CPU(32BIT) |
301 static NEVER_INLINE void partitionOutOfMemoryWithLotsOfUncommitedPages() | |
300 { | 302 { |
303 #if OS(WIN) | |
304 // Crash at a special address (0x9b) | |
305 // to be easily distinguished on crash reports. | |
306 // This is because crash stack traces are inaccurate on Windows and | |
307 // partitionOutOfMemoryWithLotsOfUncommitedPages might be not included | |
308 // in the stack traces. | |
309 ((void(*)())0x9b)(); | |
Chris Evans
2014/11/12 23:01:30
Nit: should probably use reinterpret_cast to compl
hiroshige
2014/11/13 06:26:31
Done.
| |
310 #endif | |
311 | |
312 // On non-Windows environment, IMMEDIATE_CRASH is sufficient | |
313 // because partitionOutOfMemoryWithLotsOfUncommitedPages will appear | |
314 // in crash stack traces. | |
315 IMMEDIATE_CRASH(); | |
316 } | |
317 #endif | |
318 | |
319 static NEVER_INLINE void partitionOutOfMemory(const PartitionRootBase* root) | |
320 { | |
321 #if CPU(32BIT) | |
322 // Check whether this OOM is due to a lot of super pages that are allocated | |
323 // but not committed, probably due to http://crbug.com/421387. | |
324 if (root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages - root- >totalSizeOfCommittedPages > kReasonableSizeOfUnusedPages) { | |
325 partitionOutOfMemoryWithLotsOfUncommitedPages(); | |
326 } | |
327 #endif | |
301 IMMEDIATE_CRASH(); | 328 IMMEDIATE_CRASH(); |
302 } | 329 } |
303 | 330 |
304 static ALWAYS_INLINE void partitionDecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) | 331 static ALWAYS_INLINE void partitionDecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) |
305 { | 332 { |
306 decommitSystemPages(addr, len); | 333 decommitSystemPages(addr, len); |
307 ASSERT(root->totalSizeOfCommittedPages > len); | 334 ASSERT(root->totalSizeOfCommittedPages >= len); |
308 root->totalSizeOfCommittedPages -= len; | 335 root->totalSizeOfCommittedPages -= len; |
309 } | 336 } |
310 | 337 |
311 static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) | 338 static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) |
312 { | 339 { |
313 recommitSystemPages(addr, len); | 340 recommitSystemPages(addr, len); |
314 root->totalSizeOfCommittedPages += len; | 341 root->totalSizeOfCommittedPages += len; |
342 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
315 } | 343 } |
316 | 344 |
317 static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, int flags, uint16_t numPartitionPages) | 345 static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, int flags, uint16_t numPartitionPages) |
318 { | 346 { |
319 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPage) % kPartitionPa geSize)); | 347 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPage) % kPartitionPa geSize)); |
320 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPageEnd) % kPartitio nPageSize)); | 348 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPageEnd) % kPartitio nPageSize)); |
321 RELEASE_ASSERT(numPartitionPages <= kNumPartitionPagesPerSuperPage); | 349 RELEASE_ASSERT(numPartitionPages <= kNumPartitionPagesPerSuperPage); |
322 size_t totalSize = kPartitionPageSize * numPartitionPages; | 350 size_t totalSize = kPartitionPageSize * numPartitionPages; |
323 size_t numPartitionPagesLeft = (root->nextPartitionPageEnd - root->nextParti tionPage) >> kPartitionPageShift; | 351 size_t numPartitionPagesLeft = (root->nextPartitionPageEnd - root->nextParti tionPage) >> kPartitionPageShift; |
324 if (LIKELY(numPartitionPagesLeft >= numPartitionPages)) { | 352 if (LIKELY(numPartitionPagesLeft >= numPartitionPages)) { |
325 // In this case, we can still hand out pages from the current super page | 353 // In this case, we can still hand out pages from the current super page |
326 // allocation. | 354 // allocation. |
327 char* ret = root->nextPartitionPage; | 355 char* ret = root->nextPartitionPage; |
328 root->nextPartitionPage += totalSize; | 356 root->nextPartitionPage += totalSize; |
329 root->totalSizeOfCommittedPages += totalSize; | 357 root->totalSizeOfCommittedPages += totalSize; |
358 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages); | |
330 return ret; | 359 return ret; |
331 } | 360 } |
332 | 361 |
333 // Need a new super page. | 362 // Need a new super page. |
334 char* requestedAddress = root->nextSuperPage; | 363 char* requestedAddress = root->nextSuperPage; |
335 char* superPage = reinterpret_cast<char*>(allocPages(requestedAddress, kSupe rPageSize, kSuperPageSize)); | 364 char* superPage = reinterpret_cast<char*>(allocPages(requestedAddress, kSupe rPageSize, kSuperPageSize)); |
336 if (UNLIKELY(!superPage)) | 365 if (UNLIKELY(!superPage)) |
337 return 0; | 366 return 0; |
338 | 367 |
339 root->totalSizeOfSuperPages += kSuperPageSize; | 368 root->totalSizeOfSuperPages += kSuperPageSize; |
340 root->totalSizeOfCommittedPages += totalSize; | 369 root->totalSizeOfCommittedPages += totalSize; |
370 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
341 | 371 |
342 root->nextSuperPage = superPage + kSuperPageSize; | 372 root->nextSuperPage = superPage + kSuperPageSize; |
343 char* ret = superPage + kPartitionPageSize; | 373 char* ret = superPage + kPartitionPageSize; |
344 root->nextPartitionPage = ret + totalSize; | 374 root->nextPartitionPage = ret + totalSize; |
345 root->nextPartitionPageEnd = root->nextSuperPage - kPartitionPageSize; | 375 root->nextPartitionPageEnd = root->nextSuperPage - kPartitionPageSize; |
346 // Make the first partition page in the super page a guard page, but leave a | 376 // Make the first partition page in the super page a guard page, but leave a |
347 // hole in the middle. | 377 // hole in the middle. |
348 // This is where we put page metadata and also a tiny amount of extent | 378 // This is where we put page metadata and also a tiny amount of extent |
349 // metadata. | 379 // metadata. |
350 setSystemPagesInaccessible(superPage, kSystemPageSize); | 380 setSystemPagesInaccessible(superPage, kSystemPageSize); |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
561 // a bunch of system pages more than "size": | 591 // a bunch of system pages more than "size": |
562 // - The first few system pages are the partition page in which the super | 592 // - The first few system pages are the partition page in which the super |
563 // page metadata is stored. We fault just one system page out of a partition | 593 // page metadata is stored. We fault just one system page out of a partition |
564 // page sized clump. | 594 // page sized clump. |
565 // - We add a trailing guard page. | 595 // - We add a trailing guard page. |
566 size_t mapSize = size + kPartitionPageSize + kSystemPageSize; | 596 size_t mapSize = size + kPartitionPageSize + kSystemPageSize; |
567 // Round up to the allocation granularity. | 597 // Round up to the allocation granularity. |
568 mapSize += kPageAllocationGranularityOffsetMask; | 598 mapSize += kPageAllocationGranularityOffsetMask; |
569 mapSize &= kPageAllocationGranularityBaseMask; | 599 mapSize &= kPageAllocationGranularityBaseMask; |
570 | 600 |
571 root->totalSizeOfCommittedPages += size + kSystemPageSize; | 601 size_t committedPageSize = size + kSystemPageSize; |
602 root->totalSizeOfCommittedPages += committedPageSize; | |
603 root->totalSizeOfDirectMappedPages += committedPageSize; | |
604 ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root ->totalSizeOfDirectMappedPages); | |
572 | 605 |
573 // TODO: we may want to let the operating system place these allocations | 606 // TODO: we may want to let the operating system place these allocations |
574 // where it pleases. On 32-bit, this might limit address space | 607 // where it pleases. On 32-bit, this might limit address space |
575 // fragmentation and on 64-bit, this might have useful savings for TLB | 608 // fragmentation and on 64-bit, this might have useful savings for TLB |
576 // and page table overhead. | 609 // and page table overhead. |
577 // TODO: if upsizing realloc()s are common on large sizes, we could | 610 // TODO: if upsizing realloc()s are common on large sizes, we could |
578 // consider over-allocating address space on 64-bit, "just in case". | 611 // consider over-allocating address space on 64-bit, "just in case". |
579 // TODO: consider pre-populating page tables (e.g. MAP_POPULATE on Linux, | 612 // TODO: consider pre-populating page tables (e.g. MAP_POPULATE on Linux, |
580 // MADV_WILLNEED on POSIX). | 613 // MADV_WILLNEED on POSIX). |
581 // TODO: these pages will be zero-filled. Consider internalizing an | 614 // TODO: these pages will be zero-filled. Consider internalizing an |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
617 | 650 |
618 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) | 651 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) |
619 { | 652 { |
620 size_t unmapSize = partitionPageToDirectMapExtent(page)->mapSize; | 653 size_t unmapSize = partitionPageToDirectMapExtent(page)->mapSize; |
621 | 654 |
622 // Add on the size of the trailing guard page and preceeding partition | 655 // Add on the size of the trailing guard page and preceeding partition |
623 // page. | 656 // page. |
624 unmapSize += kPartitionPageSize + kSystemPageSize; | 657 unmapSize += kPartitionPageSize + kSystemPageSize; |
625 | 658 |
626 PartitionRootBase* root = partitionPageToRoot(page); | 659 PartitionRootBase* root = partitionPageToRoot(page); |
627 root->totalSizeOfCommittedPages -= page->bucket->slotSize + kSystemPageSize; | 660 size_t uncommittedPageSize = page->bucket->slotSize + kSystemPageSize; |
661 ASSERT(root->totalSizeOfCommittedPages >= uncommittedPageSize); | |
662 root->totalSizeOfCommittedPages -= uncommittedPageSize; | |
663 ASSERT(root->totalSizeOfDirectMappedPages >= uncommittedPageSize); | |
664 root->totalSizeOfDirectMappedPages -= uncommittedPageSize; | |
628 | 665 |
629 ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask)); | 666 ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask)); |
630 | 667 |
631 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); | 668 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); |
632 // Account for the mapping starting a partition page before the actual | 669 // Account for the mapping starting a partition page before the actual |
633 // allocation address. | 670 // allocation address. |
634 ptr -= kPartitionPageSize; | 671 ptr -= kPartitionPageSize; |
635 | 672 |
636 freePages(ptr, unmapSize); | 673 freePages(ptr, unmapSize); |
637 } | 674 } |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
702 return partitionPageAllocAndFillFreelist(newPage); | 739 return partitionPageAllocAndFillFreelist(newPage); |
703 | 740 |
704 partitionAllocSlowPathFailed: | 741 partitionAllocSlowPathFailed: |
705 if (returnNull) { | 742 if (returnNull) { |
706 // If we get here, we will set the active page to null, which is an | 743 // If we get here, we will set the active page to null, which is an |
707 // invalid state. To support continued use of this bucket, we need to | 744 // invalid state. To support continued use of this bucket, we need to |
708 // restore a valid state, by setting the active page to the seed page. | 745 // restore a valid state, by setting the active page to the seed page. |
709 bucket->activePagesHead = &PartitionRootGeneric::gSeedPage; | 746 bucket->activePagesHead = &PartitionRootGeneric::gSeedPage; |
710 return nullptr; | 747 return nullptr; |
711 } | 748 } |
712 partitionOutOfMemory(); | 749 partitionOutOfMemory(root); |
713 return nullptr; | 750 return nullptr; |
714 } | 751 } |
715 | 752 |
716 static ALWAYS_INLINE void partitionFreePage(PartitionRootBase* root, PartitionPa ge* page) | 753 static ALWAYS_INLINE void partitionFreePage(PartitionRootBase* root, PartitionPa ge* page) |
717 { | 754 { |
718 ASSERT(page->freelistHead); | 755 ASSERT(page->freelistHead); |
719 ASSERT(!page->numAllocatedSlots); | 756 ASSERT(!page->numAllocatedSlots); |
720 partitionUnusePage(root, page); | 757 partitionUnusePage(root, page); |
721 // We actually leave the freed page in the active list. We'll sweep it on | 758 // We actually leave the freed page in the active list. We'll sweep it on |
722 // to the free page list when we next walk the active page list. Pulling | 759 // to the free page list when we next walk the active page list. Pulling |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
983 printf("total live: %zu bytes\n", totalLive); | 1020 printf("total live: %zu bytes\n", totalLive); |
984 printf("total resident: %zu bytes\n", totalResident); | 1021 printf("total resident: %zu bytes\n", totalResident); |
985 printf("total freeable: %zu bytes\n", totalFreeable); | 1022 printf("total freeable: %zu bytes\n", totalFreeable); |
986 fflush(stdout); | 1023 fflush(stdout); |
987 } | 1024 } |
988 | 1025 |
989 #endif // !NDEBUG | 1026 #endif // !NDEBUG |
990 | 1027 |
991 } // namespace WTF | 1028 } // namespace WTF |
992 | 1029 |
OLD | NEW |