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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 COMPILE_ASSERT(WTF::kGenericSmallestBucket == 8, generic_smallest_bucket); | 53 COMPILE_ASSERT(WTF::kGenericSmallestBucket == 8, generic_smallest_bucket); |
54 COMPILE_ASSERT(WTF::kGenericMaxBucketed == 983040, generic_max_bucketed); | 54 COMPILE_ASSERT(WTF::kGenericMaxBucketed == 983040, generic_max_bucketed); |
55 | 55 |
56 namespace WTF { | 56 namespace WTF { |
57 | 57 |
58 int PartitionRootBase::gInitializedLock = 0; | 58 int PartitionRootBase::gInitializedLock = 0; |
59 bool PartitionRootBase::gInitialized = false; | 59 bool PartitionRootBase::gInitialized = false; |
60 PartitionPage PartitionRootBase::gSeedPage; | 60 PartitionPage PartitionRootBase::gSeedPage; |
61 PartitionBucket PartitionRootBase::gPagedBucket; | 61 PartitionBucket PartitionRootBase::gPagedBucket; |
62 | 62 |
63 static size_t partitionBucketNumSystemPages(size_t size) | 63 static uint16_t partitionBucketNumSystemPages(size_t size) |
64 { | 64 { |
65 // This works out reasonably for the current bucket sizes of the generic | 65 // This works out reasonably for the current bucket sizes of the generic |
66 // allocator, and the current values of partition page size and constants. | 66 // allocator, and the current values of partition page size and constants. |
67 // Specifically, we have enough room to always pack the slots perfectly into | 67 // Specifically, we have enough room to always pack the slots perfectly into |
68 // some number of system pages. The only waste is the waste associated with | 68 // some number of system pages. The only waste is the waste associated with |
69 // unfaulted pages (i.e. wasted address space). | 69 // unfaulted pages (i.e. wasted address space). |
70 // TODO: we end up using a lot of system pages for very small sizes. For | 70 // TODO: we end up using a lot of system pages for very small sizes. For |
71 // example, we'll use 12 system pages for slot size 24. The slot size is | 71 // example, we'll use 12 system pages for slot size 24. The slot size is |
72 // so small that the waste would be tiny with just 4, or 1, system pages. | 72 // so small that the waste would be tiny with just 4, or 1, system pages. |
73 // Later, we can investigate whether there are anti-fragmentation benefits | 73 // Later, we can investigate whether there are anti-fragmentation benefits |
74 // to using fewer system pages. | 74 // to using fewer system pages. |
75 double bestWasteRatio = 1.0f; | 75 double bestWasteRatio = 1.0f; |
76 size_t bestPages = 0; | 76 uint16_t bestPages = 0; |
77 if (size > kMaxSystemPagesPerSlotSpan * kSystemPageSize) { | 77 if (size > kMaxSystemPagesPerSlotSpan * kSystemPageSize) { |
78 ASSERT(!(size % kSystemPageSize)); | 78 ASSERT(!(size % kSystemPageSize)); |
79 return size / kSystemPageSize; | 79 return static_cast<uint16_t>(size / kSystemPageSize); |
80 } | 80 } |
81 ASSERT(size <= kMaxSystemPagesPerSlotSpan * kSystemPageSize); | 81 ASSERT(size <= kMaxSystemPagesPerSlotSpan * kSystemPageSize); |
82 for (size_t i = kNumSystemPagesPerPartitionPage - 1; i <= kMaxSystemPagesPer
SlotSpan; ++i) { | 82 for (uint16_t i = kNumSystemPagesPerPartitionPage - 1; i <= kMaxSystemPagesP
erSlotSpan; ++i) { |
83 size_t pageSize = kSystemPageSize * i; | 83 size_t pageSize = kSystemPageSize * i; |
84 size_t numSlots = pageSize / size; | 84 size_t numSlots = pageSize / size; |
85 size_t waste = pageSize - (numSlots * size); | 85 size_t waste = pageSize - (numSlots * size); |
86 // Leaving a page unfaulted is not free; the page will occupy an empty p
age table entry. | 86 // Leaving a page unfaulted is not free; the page will occupy an empty p
age table entry. |
87 // Make a simple attempt to account for that. | 87 // Make a simple attempt to account for that. |
88 size_t numRemainderPages = i & (kNumSystemPagesPerPartitionPage - 1); | 88 size_t numRemainderPages = i & (kNumSystemPagesPerPartitionPage - 1); |
89 size_t numUnfaultedPages = numRemainderPages ? (kNumSystemPagesPerPartit
ionPage - numRemainderPages) : 0; | 89 size_t numUnfaultedPages = numRemainderPages ? (kNumSystemPagesPerPartit
ionPage - numRemainderPages) : 0; |
90 waste += sizeof(void*) * numUnfaultedPages; | 90 waste += sizeof(void*) * numUnfaultedPages; |
91 double wasteRatio = (double) waste / (double) pageSize; | 91 double wasteRatio = (double) waste / (double) pageSize; |
92 if (wasteRatio < bestWasteRatio) { | 92 if (wasteRatio < bestWasteRatio) { |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 ASSERT(root->totalSizeOfCommittedPages > len); | 315 ASSERT(root->totalSizeOfCommittedPages > len); |
316 root->totalSizeOfCommittedPages -= len; | 316 root->totalSizeOfCommittedPages -= len; |
317 } | 317 } |
318 | 318 |
319 static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root,
void* addr, size_t len) | 319 static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root,
void* addr, size_t len) |
320 { | 320 { |
321 recommitSystemPages(addr, len); | 321 recommitSystemPages(addr, len); |
322 root->totalSizeOfCommittedPages += len; | 322 root->totalSizeOfCommittedPages += len; |
323 } | 323 } |
324 | 324 |
325 static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root,
int flags, size_t numPartitionPages) | 325 static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root,
int flags, uint16_t numPartitionPages) |
326 { | 326 { |
327 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPage) % kPartitionPa
geSize)); | 327 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPage) % kPartitionPa
geSize)); |
328 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPageEnd) % kPartitio
nPageSize)); | 328 ASSERT(!(reinterpret_cast<uintptr_t>(root->nextPartitionPageEnd) % kPartitio
nPageSize)); |
329 RELEASE_ASSERT(numPartitionPages <= kNumPartitionPagesPerSuperPage); | 329 RELEASE_ASSERT(numPartitionPages <= kNumPartitionPagesPerSuperPage); |
330 size_t totalSize = kPartitionPageSize * numPartitionPages; | 330 size_t totalSize = kPartitionPageSize * numPartitionPages; |
331 root->totalSizeOfCommittedPages += totalSize; | 331 root->totalSizeOfCommittedPages += totalSize; |
332 size_t numPartitionPagesLeft = (root->nextPartitionPageEnd - root->nextParti
tionPage) >> kPartitionPageShift; | 332 size_t numPartitionPagesLeft = (root->nextPartitionPageEnd - root->nextParti
tionPage) >> kPartitionPageShift; |
333 if (LIKELY(numPartitionPagesLeft >= numPartitionPages)) { | 333 if (LIKELY(numPartitionPagesLeft >= numPartitionPages)) { |
334 // In this case, we can still hand out pages from the current super page | 334 // In this case, we can still hand out pages from the current super page |
335 // allocation. | 335 // allocation. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 return ret; | 397 return ret; |
398 } | 398 } |
399 | 399 |
400 static ALWAYS_INLINE void partitionUnusePage(PartitionRootBase* root, PartitionP
age* page) | 400 static ALWAYS_INLINE void partitionUnusePage(PartitionRootBase* root, PartitionP
age* page) |
401 { | 401 { |
402 ASSERT(page->bucket->numSystemPagesPerSlotSpan); | 402 ASSERT(page->bucket->numSystemPagesPerSlotSpan); |
403 void* addr = partitionPageToPointer(page); | 403 void* addr = partitionPageToPointer(page); |
404 partitionDecommitSystemPages(root, addr, page->bucket->numSystemPagesPerSlot
Span * kSystemPageSize); | 404 partitionDecommitSystemPages(root, addr, page->bucket->numSystemPagesPerSlot
Span * kSystemPageSize); |
405 } | 405 } |
406 | 406 |
407 static ALWAYS_INLINE size_t partitionBucketSlots(const PartitionBucket* bucket) | 407 static ALWAYS_INLINE uint16_t partitionBucketSlots(const PartitionBucket* bucket
) |
408 { | 408 { |
409 return (bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / bucket->slotS
ize; | 409 return static_cast<uint16_t>((bucket->numSystemPagesPerSlotSpan * kSystemPag
eSize) / bucket->slotSize); |
410 } | 410 } |
411 | 411 |
412 static ALWAYS_INLINE size_t partitionBucketPartitionPages(const PartitionBucket*
bucket) | 412 static ALWAYS_INLINE uint16_t partitionBucketPartitionPages(const PartitionBucke
t* bucket) |
413 { | 413 { |
414 return (bucket->numSystemPagesPerSlotSpan + (kNumSystemPagesPerPartitionPage
- 1)) / kNumSystemPagesPerPartitionPage; | 414 return (bucket->numSystemPagesPerSlotSpan + (kNumSystemPagesPerPartitionPage
- 1)) / kNumSystemPagesPerPartitionPage; |
415 } | 415 } |
416 | 416 |
417 static ALWAYS_INLINE void partitionPageReset(PartitionPage* page, PartitionBucke
t* bucket) | 417 static ALWAYS_INLINE void partitionPageReset(PartitionPage* page, PartitionBucke
t* bucket) |
418 { | 418 { |
419 ASSERT(page != &PartitionRootGeneric::gSeedPage); | 419 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
420 page->numAllocatedSlots = 0; | 420 page->numAllocatedSlots = 0; |
421 page->numUnprovisionedSlots = partitionBucketSlots(bucket); | 421 page->numUnprovisionedSlots = partitionBucketSlots(bucket); |
422 ASSERT(page->numUnprovisionedSlots); | 422 ASSERT(page->numUnprovisionedSlots); |
423 page->bucket = bucket; | 423 page->bucket = bucket; |
424 page->nextPage = 0; | 424 page->nextPage = 0; |
425 // NULLing the freelist is not strictly necessary but it makes an ASSERT in
partitionPageFillFreelist simpler. | 425 // NULLing the freelist is not strictly necessary but it makes an ASSERT in
partitionPageFillFreelist simpler. |
426 page->freelistHead = 0; | 426 page->freelistHead = 0; |
427 page->pageOffset = 0; | 427 page->pageOffset = 0; |
428 page->freeCacheIndex = -1; | 428 page->freeCacheIndex = -1; |
429 size_t numPartitionPages = partitionBucketPartitionPages(bucket); | 429 uint16_t numPartitionPages = partitionBucketPartitionPages(bucket); |
430 size_t i; | |
431 char* pageCharPtr = reinterpret_cast<char*>(page); | 430 char* pageCharPtr = reinterpret_cast<char*>(page); |
432 for (i = 1; i < numPartitionPages; ++i) { | 431 for (uint16_t i = 1; i < numPartitionPages; ++i) { |
433 pageCharPtr += kPageMetadataSize; | 432 pageCharPtr += kPageMetadataSize; |
434 PartitionPage* secondaryPage = reinterpret_cast<PartitionPage*>(pageChar
Ptr); | 433 PartitionPage* secondaryPage = reinterpret_cast<PartitionPage*>(pageChar
Ptr); |
435 secondaryPage->pageOffset = i; | 434 secondaryPage->pageOffset = i; |
436 } | 435 } |
437 } | 436 } |
438 | 437 |
439 static ALWAYS_INLINE char* partitionPageAllocAndFillFreelist(PartitionPage* page
) | 438 static ALWAYS_INLINE char* partitionPageAllocAndFillFreelist(PartitionPage* page
) |
440 { | 439 { |
441 ASSERT(page != &PartitionRootGeneric::gSeedPage); | 440 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
442 size_t numSlots = page->numUnprovisionedSlots; | 441 uint16_t numSlots = page->numUnprovisionedSlots; |
443 ASSERT(numSlots); | 442 ASSERT(numSlots); |
444 PartitionBucket* bucket = page->bucket; | 443 PartitionBucket* bucket = page->bucket; |
445 // We should only get here when _every_ slot is either used or unprovisioned
. | 444 // We should only get here when _every_ slot is either used or unprovisioned
. |
446 // (The third state is "on the freelist". If we have a non-empty freelist, w
e should not get here.) | 445 // (The third state is "on the freelist". If we have a non-empty freelist, w
e should not get here.) |
447 ASSERT(numSlots + page->numAllocatedSlots == partitionBucketSlots(bucket)); | 446 ASSERT(numSlots + page->numAllocatedSlots == partitionBucketSlots(bucket)); |
448 // Similarly, make explicitly sure that the freelist is empty. | 447 // Similarly, make explicitly sure that the freelist is empty. |
449 ASSERT(!page->freelistHead); | 448 ASSERT(!page->freelistHead); |
450 ASSERT(page->numAllocatedSlots >= 0); | 449 ASSERT(page->numAllocatedSlots >= 0); |
451 | 450 |
452 size_t size = bucket->slotSize; | 451 size_t size = bucket->slotSize; |
453 char* base = reinterpret_cast<char*>(partitionPageToPointer(page)); | 452 char* base = reinterpret_cast<char*>(partitionPageToPointer(page)); |
454 char* returnObject = base + (size * page->numAllocatedSlots); | 453 char* returnObject = base + (size * page->numAllocatedSlots); |
455 char* firstFreelistPointer = returnObject + size; | 454 char* firstFreelistPointer = returnObject + size; |
456 char* firstFreelistPointerExtent = firstFreelistPointer + sizeof(PartitionFr
eelistEntry*); | 455 char* firstFreelistPointerExtent = firstFreelistPointer + sizeof(PartitionFr
eelistEntry*); |
457 // Our goal is to fault as few system pages as possible. We calculate the | 456 // Our goal is to fault as few system pages as possible. We calculate the |
458 // page containing the "end" of the returned slot, and then allow freelist | 457 // page containing the "end" of the returned slot, and then allow freelist |
459 // pointers to be written up to the end of that page. | 458 // pointers to be written up to the end of that page. |
460 char* subPageLimit = reinterpret_cast<char*>((reinterpret_cast<uintptr_t>(fi
rstFreelistPointer) + kSystemPageOffsetMask) & kSystemPageBaseMask); | 459 char* subPageLimit = reinterpret_cast<char*>((reinterpret_cast<uintptr_t>(fi
rstFreelistPointer) + kSystemPageOffsetMask) & kSystemPageBaseMask); |
461 char* slotsLimit = returnObject + (size * page->numUnprovisionedSlots); | 460 char* slotsLimit = returnObject + (size * page->numUnprovisionedSlots); |
462 char* freelistLimit = subPageLimit; | 461 char* freelistLimit = subPageLimit; |
463 if (UNLIKELY(slotsLimit < freelistLimit)) | 462 if (UNLIKELY(slotsLimit < freelistLimit)) |
464 freelistLimit = slotsLimit; | 463 freelistLimit = slotsLimit; |
465 | 464 |
466 size_t numNewFreelistEntries = 0; | 465 uint16_t numNewFreelistEntries = 0; |
467 if (LIKELY(firstFreelistPointerExtent <= freelistLimit)) { | 466 if (LIKELY(firstFreelistPointerExtent <= freelistLimit)) { |
468 // Only consider used space in the slot span. If we consider wasted | 467 // Only consider used space in the slot span. If we consider wasted |
469 // space, we may get an off-by-one when a freelist pointer fits in the | 468 // space, we may get an off-by-one when a freelist pointer fits in the |
470 // wasted space, but a slot does not. | 469 // wasted space, but a slot does not. |
471 // We know we can fit at least one freelist pointer. | 470 // We know we can fit at least one freelist pointer. |
472 numNewFreelistEntries = 1; | 471 numNewFreelistEntries = 1; |
473 // Any further entries require space for the whole slot span. | 472 // Any further entries require space for the whole slot span. |
474 numNewFreelistEntries += (freelistLimit - firstFreelistPointerExtent) /
size; | 473 numNewFreelistEntries += static_cast<uint16_t>((freelistLimit - firstFre
elistPointerExtent) / size); |
475 } | 474 } |
476 | 475 |
477 // We always return an object slot -- that's the +1 below. | 476 // We always return an object slot -- that's the +1 below. |
478 // We do not neccessarily create any new freelist entries, because we cross
sub page boundaries frequently for large bucket sizes. | 477 // We do not neccessarily create any new freelist entries, because we cross
sub page boundaries frequently for large bucket sizes. |
479 ASSERT(numNewFreelistEntries + 1 <= numSlots); | 478 ASSERT(numNewFreelistEntries + 1 <= numSlots); |
480 numSlots -= (numNewFreelistEntries + 1); | 479 numSlots -= (numNewFreelistEntries + 1); |
481 page->numUnprovisionedSlots = numSlots; | 480 page->numUnprovisionedSlots = numSlots; |
482 page->numAllocatedSlots++; | 481 page->numAllocatedSlots++; |
483 | 482 |
484 if (LIKELY(numNewFreelistEntries)) { | 483 if (LIKELY(numNewFreelistEntries)) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
532 ASSERT(page->numAllocatedSlots >= 0); | 531 ASSERT(page->numAllocatedSlots >= 0); |
533 if (LIKELY(page->numAllocatedSlots == 0)) { | 532 if (LIKELY(page->numAllocatedSlots == 0)) { |
534 ASSERT(page->freeCacheIndex == -1); | 533 ASSERT(page->freeCacheIndex == -1); |
535 // We hit a free page, so shepherd it on to the free page list. | 534 // We hit a free page, so shepherd it on to the free page list. |
536 page->nextPage = bucket->freePagesHead; | 535 page->nextPage = bucket->freePagesHead; |
537 bucket->freePagesHead = page; | 536 bucket->freePagesHead = page; |
538 } else { | 537 } else { |
539 // If we get here, we found a full page. Skip over it too, and also | 538 // If we get here, we found a full page. Skip over it too, and also |
540 // tag it as full (via a negative value). We need it tagged so that | 539 // tag it as full (via a negative value). We need it tagged so that |
541 // free'ing can tell, and move it back into the active page list. | 540 // free'ing can tell, and move it back into the active page list. |
542 ASSERT(page->numAllocatedSlots == static_cast<int>(partitionBucketSl
ots(bucket))); | 541 ASSERT(page->numAllocatedSlots == partitionBucketSlots(bucket)); |
543 page->numAllocatedSlots = -page->numAllocatedSlots; | 542 page->numAllocatedSlots = -page->numAllocatedSlots; |
544 ++bucket->numFullPages; | 543 ++bucket->numFullPages; |
545 // numFullPages is a uint16_t for efficient packing so guard against | 544 // numFullPages is a uint16_t for efficient packing so guard against |
546 // overflow to be safe. | 545 // overflow to be safe. |
547 RELEASE_ASSERT(bucket->numFullPages); | 546 RELEASE_ASSERT(bucket->numFullPages); |
548 // Not necessary but might help stop accidents. | 547 // Not necessary but might help stop accidents. |
549 page->nextPage = 0; | 548 page->nextPage = 0; |
550 } | 549 } |
551 } | 550 } |
552 | 551 |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
686 ASSERT(newPage != &PartitionRootGeneric::gSeedPage); | 685 ASSERT(newPage != &PartitionRootGeneric::gSeedPage); |
687 ASSERT(!newPage->freelistHead); | 686 ASSERT(!newPage->freelistHead); |
688 ASSERT(!newPage->numAllocatedSlots); | 687 ASSERT(!newPage->numAllocatedSlots); |
689 ASSERT(!newPage->numUnprovisionedSlots); | 688 ASSERT(!newPage->numUnprovisionedSlots); |
690 ASSERT(newPage->freeCacheIndex == -1); | 689 ASSERT(newPage->freeCacheIndex == -1); |
691 bucket->freePagesHead = newPage->nextPage; | 690 bucket->freePagesHead = newPage->nextPage; |
692 void* addr = partitionPageToPointer(newPage); | 691 void* addr = partitionPageToPointer(newPage); |
693 partitionRecommitSystemPages(root, addr, newPage->bucket->numSystemPages
PerSlotSpan * kSystemPageSize); | 692 partitionRecommitSystemPages(root, addr, newPage->bucket->numSystemPages
PerSlotSpan * kSystemPageSize); |
694 } else { | 693 } else { |
695 // Third. If we get here, we need a brand new page. | 694 // Third. If we get here, we need a brand new page. |
696 size_t numPartitionPages = partitionBucketPartitionPages(bucket); | 695 uint16_t numPartitionPages = partitionBucketPartitionPages(bucket); |
697 void* rawNewPage = partitionAllocPartitionPages(root, flags, numPartitio
nPages); | 696 void* rawNewPage = partitionAllocPartitionPages(root, flags, numPartitio
nPages); |
698 if (UNLIKELY(!rawNewPage)) { | 697 if (UNLIKELY(!rawNewPage)) { |
699 ASSERT(returnNull); | 698 ASSERT(returnNull); |
700 return 0; | 699 return 0; |
701 } | 700 } |
702 // Skip the alignment check because it depends on page->bucket, which is
not yet set. | 701 // Skip the alignment check because it depends on page->bucket, which is
not yet set. |
703 newPage = partitionPointerToPageNoAlignmentCheck(rawNewPage); | 702 newPage = partitionPointerToPageNoAlignmentCheck(rawNewPage); |
704 } | 703 } |
705 | 704 |
706 partitionPageReset(newPage, bucket); | 705 partitionPageReset(newPage, bucket); |
(...skipping 20 matching lines...) Expand all Loading... |
727 PartitionRootBase* root = partitionPageToRoot(page); | 726 PartitionRootBase* root = partitionPageToRoot(page); |
728 | 727 |
729 // If the page is already registered as empty, give it another life. | 728 // If the page is already registered as empty, give it another life. |
730 if (page->freeCacheIndex != -1) { | 729 if (page->freeCacheIndex != -1) { |
731 ASSERT(page->freeCacheIndex >= 0); | 730 ASSERT(page->freeCacheIndex >= 0); |
732 ASSERT(static_cast<unsigned>(page->freeCacheIndex) < kMaxFreeableSpans); | 731 ASSERT(static_cast<unsigned>(page->freeCacheIndex) < kMaxFreeableSpans); |
733 ASSERT(root->globalEmptyPageRing[page->freeCacheIndex] == page); | 732 ASSERT(root->globalEmptyPageRing[page->freeCacheIndex] == page); |
734 root->globalEmptyPageRing[page->freeCacheIndex] = 0; | 733 root->globalEmptyPageRing[page->freeCacheIndex] = 0; |
735 } | 734 } |
736 | 735 |
737 size_t currentIndex = root->globalEmptyPageRingIndex; | 736 int16_t currentIndex = root->globalEmptyPageRingIndex; |
738 PartitionPage* pageToFree = root->globalEmptyPageRing[currentIndex]; | 737 PartitionPage* pageToFree = root->globalEmptyPageRing[currentIndex]; |
739 // The page might well have been re-activated, filled up, etc. before we get | 738 // The page might well have been re-activated, filled up, etc. before we get |
740 // around to looking at it here. | 739 // around to looking at it here. |
741 if (pageToFree) { | 740 if (pageToFree) { |
742 ASSERT(pageToFree != &PartitionRootBase::gSeedPage); | 741 ASSERT(pageToFree != &PartitionRootBase::gSeedPage); |
743 ASSERT(pageToFree->freeCacheIndex >= 0); | 742 ASSERT(pageToFree->freeCacheIndex >= 0); |
744 ASSERT(static_cast<unsigned>(pageToFree->freeCacheIndex) < kMaxFreeableS
pans); | 743 ASSERT(static_cast<unsigned>(pageToFree->freeCacheIndex) < kMaxFreeableS
pans); |
745 ASSERT(pageToFree == root->globalEmptyPageRing[pageToFree->freeCacheInde
x]); | 744 ASSERT(pageToFree == root->globalEmptyPageRing[pageToFree->freeCacheInde
x]); |
746 if (!pageToFree->numAllocatedSlots && pageToFree->freelistHead) { | 745 if (!pageToFree->numAllocatedSlots && pageToFree->freelistHead) { |
747 // The page is still empty, and not freed, so _really_ free it. | 746 // The page is still empty, and not freed, so _really_ free it. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
792 } | 791 } |
793 partitionRegisterEmptyPage(page); | 792 partitionRegisterEmptyPage(page); |
794 } else { | 793 } else { |
795 // Ensure that the page is full. That's the only valid case if we | 794 // Ensure that the page is full. That's the only valid case if we |
796 // arrive here. | 795 // arrive here. |
797 ASSERT(page->numAllocatedSlots < 0); | 796 ASSERT(page->numAllocatedSlots < 0); |
798 // A transition of numAllocatedSlots from 0 to -1 is not legal, and | 797 // A transition of numAllocatedSlots from 0 to -1 is not legal, and |
799 // likely indicates a double-free. | 798 // likely indicates a double-free. |
800 RELEASE_ASSERT(page->numAllocatedSlots != -1); | 799 RELEASE_ASSERT(page->numAllocatedSlots != -1); |
801 page->numAllocatedSlots = -page->numAllocatedSlots - 2; | 800 page->numAllocatedSlots = -page->numAllocatedSlots - 2; |
802 ASSERT(page->numAllocatedSlots == static_cast<int>(partitionBucketSlots(
bucket) - 1)); | 801 ASSERT(page->numAllocatedSlots == partitionBucketSlots(bucket) - 1); |
803 // Fully used page became partially used. It must be put back on the | 802 // Fully used page became partially used. It must be put back on the |
804 // non-full page list. Also make it the current page to increase the | 803 // non-full page list. Also make it the current page to increase the |
805 // chances of it being filled up again. The old current page will be | 804 // chances of it being filled up again. The old current page will be |
806 // the next page. | 805 // the next page. |
807 page->nextPage = bucket->activePagesHead; | 806 page->nextPage = bucket->activePagesHead; |
808 bucket->activePagesHead = page; | 807 bucket->activePagesHead = page; |
809 --bucket->numFullPages; | 808 --bucket->numFullPages; |
810 // Special case: for a partition page with just a single slot, it may | 809 // Special case: for a partition page with just a single slot, it may |
811 // now be empty and we want to run it through the empty logic. | 810 // now be empty and we want to run it through the empty logic. |
812 if (UNLIKELY(page->numAllocatedSlots == 0)) | 811 if (UNLIKELY(page->numAllocatedSlots == 0)) |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
935 // Empty bucket with no freelist or full pages. Skip reporting it. | 934 // Empty bucket with no freelist or full pages. Skip reporting it. |
936 continue; | 935 continue; |
937 } | 936 } |
938 size_t numFreePages = 0; | 937 size_t numFreePages = 0; |
939 PartitionPage* freePages = bucket.freePagesHead; | 938 PartitionPage* freePages = bucket.freePagesHead; |
940 while (freePages) { | 939 while (freePages) { |
941 ++numFreePages; | 940 ++numFreePages; |
942 freePages = freePages->nextPage; | 941 freePages = freePages->nextPage; |
943 } | 942 } |
944 size_t bucketSlotSize = bucket.slotSize; | 943 size_t bucketSlotSize = bucket.slotSize; |
945 size_t bucketNumSlots = partitionBucketSlots(&bucket); | 944 uint16_t bucketNumSlots = partitionBucketSlots(&bucket); |
946 size_t bucketUsefulStorage = bucketSlotSize * bucketNumSlots; | 945 size_t bucketUsefulStorage = bucketSlotSize * bucketNumSlots; |
947 size_t bucketPageSize = bucket.numSystemPagesPerSlotSpan * kSystemPageSi
ze; | 946 size_t bucketPageSize = bucket.numSystemPagesPerSlotSpan * kSystemPageSi
ze; |
948 size_t bucketWaste = bucketPageSize - bucketUsefulStorage; | 947 size_t bucketWaste = bucketPageSize - bucketUsefulStorage; |
949 size_t numActiveBytes = bucket.numFullPages * bucketUsefulStorage; | 948 size_t numActiveBytes = bucket.numFullPages * bucketUsefulStorage; |
950 size_t numResidentBytes = bucket.numFullPages * bucketPageSize; | 949 size_t numResidentBytes = bucket.numFullPages * bucketPageSize; |
951 size_t numFreeableBytes = 0; | 950 size_t numFreeableBytes = 0; |
952 size_t numActivePages = 0; | 951 size_t numActivePages = 0; |
953 const PartitionPage* page = bucket.activePagesHead; | 952 const PartitionPage* page = bucket.activePagesHead; |
954 while (page) { | 953 while (page) { |
955 ASSERT(page != &PartitionRootGeneric::gSeedPage); | 954 ASSERT(page != &PartitionRootGeneric::gSeedPage); |
(...skipping 20 matching lines...) Expand all Loading... |
976 printf("total live: %zu bytes\n", totalLive); | 975 printf("total live: %zu bytes\n", totalLive); |
977 printf("total resident: %zu bytes\n", totalResident); | 976 printf("total resident: %zu bytes\n", totalResident); |
978 printf("total freeable: %zu bytes\n", totalFreeable); | 977 printf("total freeable: %zu bytes\n", totalFreeable); |
979 fflush(stdout); | 978 fflush(stdout); |
980 } | 979 } |
981 | 980 |
982 #endif // !NDEBUG | 981 #endif // !NDEBUG |
983 | 982 |
984 } // namespace WTF | 983 } // namespace WTF |
985 | 984 |
OLD | NEW |