Index: third_party/WebKit/Source/wtf/allocator/PartitionAlloc.h |
diff --git a/third_party/WebKit/Source/wtf/allocator/PartitionAlloc.h b/third_party/WebKit/Source/wtf/allocator/PartitionAlloc.h |
index afee3110630ed0f23e215d1a3af1c5e487964d8b..544ec59e5dc88e3df4d1825f55216a849302928b 100644 |
--- a/third_party/WebKit/Source/wtf/allocator/PartitionAlloc.h |
+++ b/third_party/WebKit/Source/wtf/allocator/PartitionAlloc.h |
@@ -66,16 +66,16 @@ |
// |
// The allocators are designed to be extremely fast, thanks to the following |
// properties and design: |
-// - Just two single (reasonably predicatable) branches in the hot / fast path for |
-// both allocating and (significantly) freeing. |
+// - Just two single (reasonably predicatable) branches in the hot / fast path |
+// for both allocating and (significantly) freeing. |
// - A minimal number of operations in the hot / fast path, with the slow paths |
-// in separate functions, leading to the possibility of inlining. |
+// in separate functions, leading to the possibility of inlining. |
// - Each partition page (which is usually multiple physical pages) has a |
-// metadata structure which allows fast mapping of free() address to an |
-// underlying bucket. |
+// metadata structure which allows fast mapping of free() address to an |
+// underlying bucket. |
// - Supports a lock-free API for fast performance in single-threaded cases. |
// - The freelist for a given bucket is split across a number of partition |
-// pages, enabling various simple tricks to try and minimize fragmentation. |
+// pages, enabling various simple tricks to try and minimize fragmentation. |
// - Fine-grained bucket sizes leading to less waste and better packing. |
// |
// The following security properties could be investigated in the future: |
@@ -149,7 +149,14 @@ static const size_t kMaxSystemPagesPerSlotSpan = |
// The layout of the super page is as follows. The sizes below are the same |
// for 32 bit and 64 bit. |
// |
-// | Guard page (4KB) | Metadata page (4KB) | Guard pages (8KB) | Slot span | Slot span | ... | Slot span | Guard page (4KB) | |
+// | Guard page (4KB) | |
+// | Metadata page (4KB) | |
+// | Guard pages (8KB) | |
+// | Slot span | |
+// | Slot span | |
+// | ... | |
+// | Slot span | |
+// | Guard page (4KB) | |
// |
// - Each slot span is a contiguous range of one or more PartitionPages. |
// - The metadata page has the following format. Note that the PartitionPage |
@@ -158,15 +165,30 @@ static const size_t kMaxSystemPagesPerSlotSpan = |
// of the slot span. Metadata accesses to other PartitionPages are |
// redirected to the first PartitionPage. |
// |
-// | SuperPageExtentEntry (32B) | PartitionPage of slot span 1 (32B, used) | PartitionPage of slot span 1 (32B, unused) | PartitionPage of slot span 1 (32B, unused) | PartitionPage of slot span 2 (32B, used) | PartitionPage of slot span 3 (32B, used) | ... | PartitionPage of slot span N (32B, unused) | |
+// | SuperPageExtentEntry (32B) | |
+// | PartitionPage of slot span 1 (32B, used) | |
+// | PartitionPage of slot span 1 (32B, unused) | |
+// | PartitionPage of slot span 1 (32B, unused) | |
+// | PartitionPage of slot span 2 (32B, used) | |
+// | PartitionPage of slot span 3 (32B, used) | |
+// | ... | |
+// | PartitionPage of slot span N (32B, unused) | |
// |
-// A direct mapped page has a similar layout to fake it looking like a super page: |
+// A direct mapped page has a similar layout to fake it looking like a super |
+// page: |
// |
-// | Guard page (4KB) | Metadata page (4KB) | Guard pages (8KB) | Direct mapped object | Guard page (4KB) | |
+// | Guard page (4KB) | |
+// | Metadata page (4KB) | |
+// | Guard pages (8KB) | |
+// | Direct mapped object | |
+// | Guard page (4KB) | |
// |
// - The metadata page has the following layout: |
// |
-// | SuperPageExtentEntry (32B) | PartitionPage (32B) | PartitionBucket (32B) | PartitionDirectMapExtent (8B) | |
+// | SuperPageExtentEntry (32B) | |
+// | PartitionPage (32B) | |
+// | PartitionBucket (32B) | |
+// | PartitionDirectMapExtent (8B) | |
static const size_t kSuperPageShift = 21; // 2MB |
static const size_t kSuperPageSize = 1 << kSuperPageShift; |
static const size_t kSuperPageOffsetMask = kSuperPageSize - 1; |
@@ -189,8 +211,9 @@ static const size_t kGenericMaxBucketedOrder = |
20; // Largest bucketed order is 1<<(20-1) (storing 512KB -> almost 1MB) |
static const size_t kGenericNumBucketedOrders = |
(kGenericMaxBucketedOrder - kGenericMinBucketedOrder) + 1; |
-static const size_t kGenericNumBucketsPerOrderBits = |
- 3; // Eight buckets per order (for the higher orders), e.g. order 8 is 128, 144, 160, ..., 240 |
+// Eight buckets per order (for the higher orders), e.g. order 8 is 128, 144, |
+// 160, ..., 240: |
+static const size_t kGenericNumBucketsPerOrderBits = 3; |
static const size_t kGenericNumBucketsPerOrder = |
1 << kGenericNumBucketsPerOrderBits; |
static const size_t kGenericNumBuckets = |
@@ -265,8 +288,8 @@ struct PartitionPage { |
PartitionFreelistEntry* freelistHead; |
PartitionPage* nextPage; |
PartitionBucket* bucket; |
- int16_t |
- numAllocatedSlots; // Deliberately signed, 0 for empty or decommitted page, -n for full pages. |
+ // Deliberately signed, 0 for empty or decommitted page, -n for full pages: |
+ int16_t numAllocatedSlots; |
uint16_t numUnprovisionedSlots; |
uint16_t pageOffset; |
int16_t emptyCacheIndex; // -1 if not in the empty cache. |
@@ -302,7 +325,8 @@ struct WTF_EXPORT PartitionRootBase { |
size_t totalSizeOfCommittedPages; |
size_t totalSizeOfSuperPages; |
size_t totalSizeOfDirectMappedPages; |
- // Invariant: totalSizeOfCommittedPages <= totalSizeOfSuperPages + totalSizeOfDirectMappedPages. |
+ // Invariant: totalSizeOfCommittedPages <= |
+ // totalSizeOfSuperPages + totalSizeOfDirectMappedPages. |
unsigned numBuckets; |
unsigned maxAllocation; |
bool initialized; |
@@ -339,16 +363,18 @@ struct PartitionRoot : public PartitionRootBase { |
} |
}; |
-// Never instantiate a PartitionRootGeneric directly, instead use PartitionAllocatorGeneric. |
+// Never instantiate a PartitionRootGeneric directly, instead use |
+// PartitionAllocatorGeneric. |
struct PartitionRootGeneric : public PartitionRootBase { |
SpinLock lock; |
// Some pre-computed constants. |
size_t orderIndexShifts[kBitsPerSizet + 1]; |
size_t orderSubIndexMasks[kBitsPerSizet + 1]; |
// The bucket lookup table lets us map a size_t to a bucket quickly. |
- // The trailing +1 caters for the overflow case for very large allocation sizes. |
- // It is one flat array instead of a 2D array because in the 2D world, we'd |
- // need to index array[blah][max+1] which risks undefined behavior. |
+ // The trailing +1 caters for the overflow case for very large allocation |
+ // sizes. It is one flat array instead of a 2D array because in the 2D |
+ // world, we'd need to index array[blah][max+1] which risks undefined |
+ // behavior. |
PartitionBucket* |
bucketLookups[((kBitsPerSizet + 1) * kGenericNumBucketsPerOrder) + 1]; |
PartitionBucket buckets[kGenericNumBuckets]; |
@@ -373,23 +399,23 @@ struct PartitionMemoryStats { |
// Struct used to retrieve memory statistics about a partition bucket. Used by |
// PartitionStatsDumper implementation. |
struct PartitionBucketMemoryStats { |
- bool isValid; // Used to check if the stats is valid. |
- bool |
- isDirectMap; // True if this is a direct mapping; size will not be unique. |
- uint32_t bucketSlotSize; // The size of the slot in bytes. |
- uint32_t |
- allocatedPageSize; // Total size the partition page allocated from the system. |
- uint32_t activeBytes; // Total active bytes used in the bucket. |
- uint32_t residentBytes; // Total bytes provisioned in the bucket. |
- uint32_t decommittableBytes; // Total bytes that could be decommitted. |
- uint32_t discardableBytes; // Total bytes that could be discarded. |
- uint32_t numFullPages; // Number of pages with all slots allocated. |
- uint32_t |
- numActivePages; // Number of pages that have at least one provisioned slot. |
- uint32_t |
- numEmptyPages; // Number of pages that are empty but not decommitted. |
- uint32_t |
- numDecommittedPages; // Number of pages that are empty and decommitted. |
+ bool isValid; // Used to check if the stats is valid. |
+ bool isDirectMap; // True if this is a direct mapping; size will not be |
+ // unique. |
+ uint32_t bucketSlotSize; // The size of the slot in bytes. |
+ uint32_t allocatedPageSize; // Total size the partition page allocated from |
+ // the system. |
+ uint32_t activeBytes; // Total active bytes used in the bucket. |
+ uint32_t residentBytes; // Total bytes provisioned in the bucket. |
+ uint32_t decommittableBytes; // Total bytes that could be decommitted. |
+ uint32_t discardableBytes; // Total bytes that could be discarded. |
+ uint32_t numFullPages; // Number of pages with all slots allocated. |
+ uint32_t numActivePages; // Number of pages that have at least one |
+ // provisioned slot. |
+ uint32_t numEmptyPages; // Number of pages that are empty |
+ // but not decommitted. |
+ uint32_t numDecommittedPages; // Number of pages that are empty |
+ // and decommitted. |
}; |
// Interface that is passed to partitionDumpStats and |
@@ -578,7 +604,8 @@ ALWAYS_INLINE PartitionPage* partitionPointerToPageNoAlignmentCheck(void* ptr) { |
PartitionPage* page = reinterpret_cast<PartitionPage*>( |
partitionSuperPageToMetadataArea(superPagePtr) + |
(partitionPageIndex << kPageMetadataShift)); |
- // Partition pages in the same slot span can share the same page object. Adjust for that. |
+ // Partition pages in the same slot span can share the same page object. |
+ // Adjust for that. |
size_t delta = page->pageOffset << kPageMetadataShift; |
page = |
reinterpret_cast<PartitionPage*>(reinterpret_cast<char*>(page) - delta); |
@@ -593,7 +620,8 @@ ALWAYS_INLINE void* partitionPageToPointer(const PartitionPage* page) { |
kPageMetadataSize)); |
uintptr_t partitionPageIndex = |
(superPageOffset - kSystemPageSize) >> kPageMetadataShift; |
- // Index 0 is invalid because it is the metadata area and the last index is invalid because it is a guard page. |
+ // Index 0 is invalid because it is the metadata area and the last index is |
+ // invalid because it is a guard page. |
ASSERT(partitionPageIndex); |
ASSERT(partitionPageIndex < kNumPartitionPagesPerSuperPage - 1); |
uintptr_t superPageBase = (pointerAsUint & kSuperPageBaseMask); |
@@ -740,12 +768,9 @@ ALWAYS_INLINE void partitionFreeWithPage(void* ptr, PartitionPage* page) { |
PartitionFreelistEntry* freelistHead = page->freelistHead; |
ASSERT(!freelistHead || partitionPointerIsValid(freelistHead)); |
SECURITY_CHECK(ptr != freelistHead); // Catches an immediate double free. |
+ // Look for double free one level deeper in debug. |
ASSERT_WITH_SECURITY_IMPLICATION( |
- !freelistHead || |
- ptr != |
- partitionFreelistMask( |
- freelistHead |
- ->next)); // Look for double free one level deeper in debug. |
+ !freelistHead || ptr != partitionFreelistMask(freelistHead->next)); |
PartitionFreelistEntry* entry = static_cast<PartitionFreelistEntry*>(ptr); |
entry->next = partitionFreelistMask(freelistHead); |
page->freelistHead = entry; |