15267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)/*
25267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * Copyright (C) 2013 Google Inc. All rights reserved.
35267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) *
45267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * modification, are permitted provided that the following conditions are
65267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * met:
75267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) *
85267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * in the documentation and/or other materials provided with the
135267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * distribution.
145267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * contributors may be used to endorse or promote products derived from
165267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * this software without specific prior written permission.
175267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) *
185267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) */
305267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
315267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "config.h"
325267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "wtf/PartitionAlloc.h"
335267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
34a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "wtf/BitwiseOperations.h"
351e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "wtf/OwnPtr.h"
361e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "wtf/PassOwnPtr.h"
375267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <gtest/gtest.h>
385267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <stdlib.h>
395267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <string.h>
405267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
418abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)#if OS(POSIX)
42521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#include <sys/mman.h>
43521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
44521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#ifndef MAP_ANONYMOUS
45521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#define MAP_ANONYMOUS MAP_ANON
46521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#endif
478abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)#endif // OS(POSIX)
48521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
49591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch#if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
505267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
515267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)namespace {
525267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
53f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)static const size_t kTestMaxAllocation = 4096;
5409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static SizeSpecificPartitionAllocator<kTestMaxAllocation> allocator;
5509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static PartitionAllocatorGeneric genericAllocator;
56f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)
5709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static const size_t kTestAllocSize = 16;
58197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if !ENABLE(ASSERT)
59f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)static const size_t kPointerOffset = 0;
60f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)static const size_t kExtraAllocSize = 0;
61f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)#else
6209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static const size_t kPointerOffset = WTF::kCookieSize;
6309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static const size_t kExtraAllocSize = WTF::kCookieSize * 2;
64f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)#endif
65f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)static const size_t kRealAllocSize = kTestAllocSize + kExtraAllocSize;
66f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)static const size_t kTestBucketIndex = kRealAllocSize >> WTF::kBucketShift;
675267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
685267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)static void TestSetup()
695267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles){
708abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    allocator.init();
7109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    genericAllocator.init();
725267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)}
735267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
745267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)static void TestShutdown()
755267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles){
76d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#ifndef NDEBUG
77d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // Test that the partition statistic dumping code works. Previously, it
78d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // bitrotted because no test calls it.
79d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    partitionDumpStats(*allocator.root());
80d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#endif
81d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
82591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // We expect no leaks in the general case. We have a test for leak
83591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    // detection.
848abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    EXPECT_TRUE(allocator.shutdown());
8509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(genericAllocator.shutdown());
865267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)}
875267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
88a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)static WTF::PartitionPage* GetFullPage(size_t size)
895267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles){
90f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    size_t realSize = size + kExtraAllocSize;
91f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    size_t bucketIdx = realSize >> WTF::kBucketShift;
928abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
9309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t numSlots = (bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / realSize;
945267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    void* first = 0;
955267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    void* last = 0;
965267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    size_t i;
975267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    for (i = 0; i < numSlots; ++i) {
988abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)        void* ptr = partitionAlloc(allocator.root(), size);
995267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        EXPECT_TRUE(ptr);
1005267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        if (!i)
10109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            first = WTF::partitionCookieFreePointerAdjust(ptr);
1025267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        else if (i == numSlots - 1)
10309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            last = WTF::partitionCookieFreePointerAdjust(ptr);
1045267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    }
10509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(WTF::partitionPointerToPage(first), WTF::partitionPointerToPage(last));
10609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (bucket->numSystemPagesPerSlotSpan == WTF::kNumSystemPagesPerPartitionPage)
10709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        EXPECT_EQ(reinterpret_cast<size_t>(first) & WTF::kPartitionPageBaseMask, reinterpret_cast<size_t>(last) & WTF::kPartitionPageBaseMask);
108a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(numSlots, static_cast<size_t>(bucket->activePagesHead->numAllocatedSlots));
10909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, bucket->activePagesHead->freelistHead);
110a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_TRUE(bucket->activePagesHead);
11109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(bucket->activePagesHead != &WTF::PartitionRootGeneric::gSeedPage);
112a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    return bucket->activePagesHead;
1135267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)}
1145267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
115a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)static void FreeFullPage(WTF::PartitionPage* page)
1165267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles){
11709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t size = page->bucket->slotSize;
11809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t numSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / size;
1195267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_EQ(numSlots, static_cast<size_t>(abs(page->numAllocatedSlots)));
120a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page));
1215267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    size_t i;
1225267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    for (i = 0; i < numSlots; ++i) {
123f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)        partitionFree(ptr + kPointerOffset);
124521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        ptr += size;
1255267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    }
1265267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)}
1275267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
12809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static void CycleFreeCache(size_t size)
12909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
13009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t realSize = size + kExtraAllocSize;
13109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t bucketIdx = realSize >> WTF::kBucketShift;
13209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
13309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ASSERT(!bucket->activePagesHead->numAllocatedSlots);
13409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
13509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    for (size_t i = 0; i < WTF::kMaxFreeableSpans; ++i) {
13609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        void* ptr = partitionAlloc(allocator.root(), size);
13709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots);
13809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        partitionFree(ptr);
13909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
14009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        EXPECT_NE(-1, bucket->activePagesHead->freeCacheIndex);
14109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
14209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
14309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
144d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)static void CycleGenericFreeCache(size_t size)
145d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){
146d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    for (size_t i = 0; i < WTF::kMaxFreeableSpans; ++i) {
147d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
148d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
149d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        WTF::PartitionBucket* bucket = page->bucket;
150d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots);
151d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        partitionFreeGeneric(genericAllocator.root(), ptr);
152d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
153d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        EXPECT_NE(-1, bucket->activePagesHead->freeCacheIndex);
154d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    }
155d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
156d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1575267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// Check that the most basic of allocate / free pairs work.
158f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, Basic)
1595267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles){
1605267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    TestSetup();
161f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
16209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WTF::PartitionPage* seedPage = &WTF::PartitionRootGeneric::gSeedPage;
1635267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
164a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_FALSE(bucket->freePagesHead);
16509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(seedPage, bucket->activePagesHead);
16609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, bucket->activePagesHead->nextPage);
1675267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
1688abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    void* ptr = partitionAlloc(allocator.root(), kTestAllocSize);
1695267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_TRUE(ptr);
170a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(kPointerOffset, reinterpret_cast<size_t>(ptr) & WTF::kPartitionPageOffsetMask);
171521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // Check that the offset appears to include a guard page.
172a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(WTF::kPartitionPageSize + kPointerOffset, reinterpret_cast<size_t>(ptr) & WTF::kSuperPageOffsetMask);
1735267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
1745267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    partitionFree(ptr);
175bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    // Expect that the last active page does not get tossed to the freelist.
176a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_FALSE(bucket->freePagesHead);
1775267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
1785267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    TestShutdown();
1795267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)}
1805267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
181591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch// Check that we can detect a memory leak.
182f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, SimpleLeak)
183591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch{
184591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    TestSetup();
1858abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    void* leakedPtr = partitionAlloc(allocator.root(), kTestAllocSize);
186f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    (void)leakedPtr;
18709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* leakedPtr2 = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
18809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    (void)leakedPtr2;
1898abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    EXPECT_FALSE(allocator.shutdown());
19009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_FALSE(genericAllocator.shutdown());
191591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch}
192591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch
1935267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// Test multiple allocations, and freelist handling.
194f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, MultiAlloc)
1955267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles){
1965267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    TestSetup();
1975267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
1988abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    char* ptr1 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
1998abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    char* ptr2 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
2005267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_TRUE(ptr1);
2015267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_TRUE(ptr2);
2025267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    ptrdiff_t diff = ptr2 - ptr1;
203f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff);
2045267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
2055267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    // Check that we re-use the just-freed slot.
2065267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    partitionFree(ptr2);
2078abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    ptr2 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
2085267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_TRUE(ptr2);
2095267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    diff = ptr2 - ptr1;
210f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff);
2115267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    partitionFree(ptr1);
2128abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    ptr1 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
2135267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_TRUE(ptr1);
2145267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    diff = ptr2 - ptr1;
215f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff);
2165267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
2178abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    char* ptr3 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
2185267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_TRUE(ptr3);
2195267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    diff = ptr3 - ptr1;
220f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize * 2), diff);
2215267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
2225267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    partitionFree(ptr1);
2235267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    partitionFree(ptr2);
2245267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    partitionFree(ptr3);
2255267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
2265267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    TestShutdown();
2275267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)}
2285267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
2295267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// Test a bucket with multiple pages.
230f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, MultiPages)
2315267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles){
2325267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    TestSetup();
233f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
2345267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
235a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page = GetFullPage(kTestAllocSize);
236f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page);
237a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_FALSE(bucket->freePagesHead);
238a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page, bucket->activePagesHead);
23909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page->nextPage);
240a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(0, page->numAllocatedSlots);
2415267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
242521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    page = GetFullPage(kTestAllocSize);
243a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize);
2445267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
245a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page2, bucket->activePagesHead);
24609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page2->nextPage);
247a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(reinterpret_cast<uintptr_t>(partitionPageToPointer(page)) & WTF::kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer(page2)) & WTF::kSuperPageBaseMask);
2485267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
249a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    // Fully free the non-current page. It should not be freelisted because
25009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // there is no other immediately useable page. The other page is full.
251f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page);
2525267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_EQ(0, page->numAllocatedSlots);
253a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_FALSE(bucket->freePagesHead);
254a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page, bucket->activePagesHead);
2555267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
2565267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    // Allocate a new page, it should pull from the freelist.
257521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    page = GetFullPage(kTestAllocSize);
258a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_FALSE(bucket->freePagesHead);
259a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page, bucket->activePagesHead);
2605267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
261f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page);
262f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page2);
2635267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_EQ(0, page->numAllocatedSlots);
26409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page2->numAllocatedSlots);
26509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page2->numUnprovisionedSlots);
26609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_NE(-1, page2->freeCacheIndex);
2675267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
2685267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    TestShutdown();
2695267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)}
2705267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
2715267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// Test some finer aspects of internal page transitions.
272f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, PageTransitions)
2735267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles){
2745267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    TestSetup();
275f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
2765267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
277a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page1 = GetFullPage(kTestAllocSize);
278a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page1, bucket->activePagesHead);
27909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page1->nextPage);
280a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize);
281a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page2, bucket->activePagesHead);
28209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page2->nextPage);
2831e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
2841e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Bounce page1 back into the non-full list then fill it up again.
285a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointerOffset;
2861e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    partitionFree(ptr);
287a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page1, bucket->activePagesHead);
2881e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    (void) partitionAlloc(allocator.root(), kTestAllocSize);
289a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page1, bucket->activePagesHead);
29009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(page2, bucket->activePagesHead->nextPage);
2911e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
2925267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    // Allocating another page at this point should cause us to scan over page1
2935267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    // (which is both full and NOT our current page), and evict it from the
2945267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    // freelist. Older code had a O(n^2) condition due to failure to do this.
295a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page3 = GetFullPage(kTestAllocSize);
296a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page3, bucket->activePagesHead);
29709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page3->nextPage);
2985267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
2995267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    // Work out a pointer into page2 and free it.
300a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    ptr = reinterpret_cast<char*>(partitionPageToPointer(page2)) + kPointerOffset;
3015267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    partitionFree(ptr);
3025267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    // Trying to allocate at this time should cause us to cycle around to page2
3035267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    // and find the recently freed slot.
3048abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    char* newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
3055267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_EQ(ptr, newPtr);
306a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page2, bucket->activePagesHead);
30709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(page3, page2->nextPage);
3085267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
3095267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    // Work out a pointer into page1 and free it. This should pull the page
310a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    // back into the list of available pages.
311a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    ptr = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointerOffset;
3125267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    partitionFree(ptr);
3135267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    // This allocation should be satisfied by page1.
3148abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
3155267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    EXPECT_EQ(ptr, newPtr);
316a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(page1, bucket->activePagesHead);
31709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(page2, page1->nextPage);
3185267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
319f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page3);
320f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page2);
321f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page1);
322521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
323a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    // Allocating whilst in this state exposed a bug, so keep the test.
324a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    ptr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
325a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    partitionFree(ptr);
326a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
327521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    TestShutdown();
328521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)}
329521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
330521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// Test some corner cases relating to page transitions in the internal
331521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// free page list metadata bucket.
332f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, FreePageListPageTransitions)
333521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles){
334521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    TestSetup();
335f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
336521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
337a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    size_t numToFillFreeListPage = WTF::kPartitionPageSize / (sizeof(WTF::PartitionPage) + kExtraAllocSize);
338bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    // The +1 is because we need to account for the fact that the current page
339bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    // never gets thrown on the freelist.
340bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    ++numToFillFreeListPage;
341a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    OwnPtr<WTF::PartitionPage*[]> pages = adoptArrayPtr(new WTF::PartitionPage*[numToFillFreeListPage]);
342bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)
343521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    size_t i;
3441e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    for (i = 0; i < numToFillFreeListPage; ++i) {
345521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        pages[i] = GetFullPage(kTestAllocSize);
346521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    }
347a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->activePagesHead);
348f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    for (i = 0; i < numToFillFreeListPage; ++i)
349f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)        FreeFullPage(pages[i]);
350a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
35109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_NE(-1, bucket->activePagesHead->nextPage->freeCacheIndex);
35209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, bucket->activePagesHead->nextPage->numAllocatedSlots);
35309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, bucket->activePagesHead->nextPage->numUnprovisionedSlots);
354521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
3551e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Allocate / free in a different bucket size so we get control of a
356bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    // different free page list. We need two pages because one will be the last
357bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    // active page and not get freed.
358a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page1 = GetFullPage(kTestAllocSize * 2);
359a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize * 2);
360f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page1);
361f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page2);
362521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
363521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // If we re-allocate all kTestAllocSize allocations, we'll pull all the
364521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // free pages and end up freeing the first page for free page objects.
365521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // It's getting a bit tricky but a nice re-entrancy is going on:
366521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // alloc(kTestAllocSize) -> pulls page from free page list ->
367521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // free(PartitionFreepagelistEntry) -> last entry in page freed ->
368521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // alloc(PartitionFreepagelistEntry).
3691e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    for (i = 0; i < numToFillFreeListPage; ++i) {
370521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        pages[i] = GetFullPage(kTestAllocSize);
371521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    }
372a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->activePagesHead);
373521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
374521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // As part of the final free-up, we'll test another re-entrancy:
375521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // free(kTestAllocSize) -> last entry in page freed ->
376521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // alloc(PartitionFreepagelistEntry) -> pulls page from free page list ->
377521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // free(PartitionFreepagelistEntry)
378f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    for (i = 0; i < numToFillFreeListPage; ++i)
379f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)        FreeFullPage(pages[i]);
380a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
38109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_NE(-1, bucket->activePagesHead->nextPage->freeCacheIndex);
38209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, bucket->activePagesHead->nextPage->numAllocatedSlots);
38309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, bucket->activePagesHead->nextPage->numUnprovisionedSlots);
3845267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
3855267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    TestShutdown();
3865267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)}
3875267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
388521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// Test a large series of allocations that cross more than one underlying
389521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// 64KB super page allocation.
390f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, MultiPageAllocs)
391521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles){
392521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    TestSetup();
393521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // This is guaranteed to cross a super page boundary because the first
394521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // partition page "slot" will be taken up by a guard page.
395a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    size_t numPagesNeeded = WTF::kNumPartitionPagesPerSuperPage;
396a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    // The super page should begin and end in a guard so we one less page in
397a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    // order to allocate a single page in the new super page.
398a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    --numPagesNeeded;
399a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
400521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    EXPECT_GT(numPagesNeeded, 1u);
401a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    OwnPtr<WTF::PartitionPage*[]> pages;
402a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    pages = adoptArrayPtr(new WTF::PartitionPage*[numPagesNeeded]);
403521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    uintptr_t firstSuperPageBase = 0;
404521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    size_t i;
405521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    for (i = 0; i < numPagesNeeded; ++i) {
406521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        pages[i] = GetFullPage(kTestAllocSize);
407a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        void* storagePtr = partitionPageToPointer(pages[i]);
408521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        if (!i)
409a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            firstSuperPageBase = reinterpret_cast<uintptr_t>(storagePtr) & WTF::kSuperPageBaseMask;
410521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        if (i == numPagesNeeded - 1) {
411a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            uintptr_t secondSuperPageBase = reinterpret_cast<uintptr_t>(storagePtr) & WTF::kSuperPageBaseMask;
412a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            uintptr_t secondSuperPageOffset = reinterpret_cast<uintptr_t>(storagePtr) & WTF::kSuperPageOffsetMask;
413521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            EXPECT_FALSE(secondSuperPageBase == firstSuperPageBase);
414a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            // Check that we allocated a guard page for the second page.
415a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)            EXPECT_EQ(WTF::kPartitionPageSize, secondSuperPageOffset);
416521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        }
417521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    }
418f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    for (i = 0; i < numPagesNeeded; ++i)
419f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)        FreeFullPage(pages[i]);
420521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
421521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    TestShutdown();
422521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)}
423521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
4241fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch// Test the generic allocation functions that can handle arbitrary sizes and
4251fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch// reallocing etc.
426f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, GenericAlloc)
4271fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch{
4281fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    TestSetup();
4291fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch
43009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr = partitionAllocGeneric(genericAllocator.root(), 1);
4311fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_TRUE(ptr);
43209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
43309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), WTF::kGenericMaxBucketed + 1);
4341fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_TRUE(ptr);
43509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
4361fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch
43709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), 1);
4381fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_TRUE(ptr);
4391fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    void* origPtr = ptr;
4401fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    char* charPtr = static_cast<char*>(ptr);
4411fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    *charPtr = 'A';
4421fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch
4431fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    // Change the size of the realloc, remaining inside the same bucket.
44409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 2);
4451fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(ptr, newPtr);
44609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1);
4471fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(ptr, newPtr);
44809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericSmallestBucket);
4493c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch    EXPECT_EQ(ptr, newPtr);
4501fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch
4511fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    // Change the size of the realloc, switching buckets.
45209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericSmallestBucket + 1);
4533c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch    EXPECT_NE(newPtr, ptr);
4541fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    // Check that the realloc copied correctly.
4551fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    char* newCharPtr = static_cast<char*>(newPtr);
4561fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(*newCharPtr, 'A');
457197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if ENABLE(ASSERT)
45819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    // Subtle: this checks for an old bug where we copied too much from the
45919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    // source of the realloc. The condition can be detected by a trashing of
46019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    // the uninitialized value in the space of the upsized allocation.
46109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(WTF::kUninitializedByte, static_cast<unsigned char>(*(newCharPtr + WTF::kGenericSmallestBucket)));
46219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#endif
4631fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    *newCharPtr = 'B';
4641fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    // The realloc moved. To check that the old allocation was freed, we can
4651fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    // do an alloc of the old allocation size and check that the old allocation
4661fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    // address is at the head of the freelist and reused.
46709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* reusedPtr = partitionAllocGeneric(genericAllocator.root(), 1);
4681fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(reusedPtr, origPtr);
46909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), reusedPtr);
4701fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch
4711fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    // Downsize the realloc.
4721fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    ptr = newPtr;
47309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1);
4741fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(newPtr, origPtr);
4751fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    newCharPtr = static_cast<char*>(newPtr);
4761fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(*newCharPtr, 'B');
4771fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    *newCharPtr = 'C';
4781fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch
4791fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    // Upsize the realloc to outside the partition.
4801fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    ptr = newPtr;
48109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericMaxBucketed + 1);
4823c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch    EXPECT_NE(newPtr, ptr);
4831fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    newCharPtr = static_cast<char*>(newPtr);
4841fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(*newCharPtr, 'C');
4851fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    *newCharPtr = 'D';
4861fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch
4871fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    // Upsize and downsize the realloc, remaining outside the partition.
4881fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    ptr = newPtr;
48909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericMaxBucketed * 10);
4901fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    newCharPtr = static_cast<char*>(newPtr);
4911fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(*newCharPtr, 'D');
4921fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    *newCharPtr = 'E';
4931fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    ptr = newPtr;
49409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericMaxBucketed * 2);
4951fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    newCharPtr = static_cast<char*>(newPtr);
4961fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(*newCharPtr, 'E');
4971fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    *newCharPtr = 'F';
4981fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch
4991fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    // Downsize the realloc to inside the partition.
5001fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    ptr = newPtr;
50109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1);
5023c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch    EXPECT_NE(newPtr, ptr);
5031fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(newPtr, origPtr);
5041fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    newCharPtr = static_cast<char*>(newPtr);
5051fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    EXPECT_EQ(*newCharPtr, 'F');
5061fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch
50709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), newPtr);
50809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestShutdown();
50909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
51009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
51109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// Test the generic allocation functions can handle some specific sizes of
51209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// interest.
513f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, GenericAllocSizes)
51409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
51509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestSetup();
51609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
51709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr = partitionAllocGeneric(genericAllocator.root(), 0);
51809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr);
51909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
52009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
52109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // kPartitionPageSize is interesting because it results in just one
52209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // allocation per page, which tripped up some corner cases.
52309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t size = WTF::kPartitionPageSize - kExtraAllocSize;
52409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), size);
52509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr);
52609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
52709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr2);
52809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
52909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Should be freeable at this point.
53009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
53109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_NE(-1, page->freeCacheIndex);
53209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr2);
53309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
53409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size = (((WTF::kPartitionPageSize * WTF::kMaxPartitionPagesPerSlotSpan) - WTF::kSystemPageSize) / 2) - kExtraAllocSize;
53509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), size);
53609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr);
53709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    memset(ptr, 'A', size);
53809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
53909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr2);
54009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr3 = partitionAllocGeneric(genericAllocator.root(), size);
54109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr3);
54209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr4 = partitionAllocGeneric(genericAllocator.root(), size);
54309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr4);
54409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
54509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
54609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WTF::PartitionPage* page2 = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr3));
54709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_NE(page, page2);
54809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
54909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
55009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr3);
55109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr2);
55209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Should be freeable at this point.
55309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_NE(-1, page->freeCacheIndex);
55409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page->numAllocatedSlots);
55509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page->numUnprovisionedSlots);
55609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* newPtr = partitionAllocGeneric(genericAllocator.root(), size);
55709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(ptr3, newPtr);
55809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    newPtr = partitionAllocGeneric(genericAllocator.root(), size);
55909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(ptr2, newPtr);
560197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if OS(LINUX) && !ENABLE(ASSERT)
56109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // On Linux, we have a guarantee that freelisting a page should cause its
56209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // contents to be nulled out. We check for null here to detect an bug we
56309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // had where a large slot size was causing us to not properly free all
56409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // resources back to the system.
565197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    // We only run the check when asserts are disabled because when they are
566197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    // enabled, the allocated area is overwritten with an "uninitialized"
567197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    // byte pattern.
56809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, *(reinterpret_cast<char*>(newPtr) + (size - 1)));
56909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#endif
57009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), newPtr);
57109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr3);
57209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr4);
57309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
57409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Can we allocate a massive (512MB) size?
57509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), 512 * 1024 * 1024);
57609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
57709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
57809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Check a more reasonable, but still direct mapped, size.
57909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Chop a system page and a byte off to test for rounding errors.
58009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size = 20 * 1024 * 1024;
58109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size -= WTF::kSystemPageSize;
58209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size -= 1;
58309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), size);
58409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    char* charPtr = reinterpret_cast<char*>(ptr);
58509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    *(charPtr + (size - 1)) = 'A';
58609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
58709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
58809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Can we free null?
58909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), 0);
59009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
59109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Do we correctly get a null for a failed allocation?
59209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, partitionAllocGenericFlags(genericAllocator.root(), WTF::PartitionAllocReturnNull, 3u * 1024 * 1024 * 1024));
59309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
59409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestShutdown();
59509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
59609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
597d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// Test that we can fetch the real allocated size after an allocation.
598f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, GenericAllocGetSize)
599d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){
600d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    TestSetup();
601d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
602d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    void* ptr;
603d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    size_t requestedSize, actualSize, predictedSize;
604d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
605d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(partitionAllocSupportsGetSize());
606d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
607d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Allocate something small.
608d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    requestedSize = 511 - kExtraAllocSize;
609d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSize);
610d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
611d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(ptr);
612d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    actualSize = partitionAllocGetSize(ptr);
613d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(predictedSize, actualSize);
614d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_LT(requestedSize, actualSize);
615d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
616d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
617d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Allocate a size that should be a perfect match for a bucket, because it
618d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // is an exact power of 2.
619d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    requestedSize = (256 * 1024) - kExtraAllocSize;
620d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSize);
621d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
622d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(ptr);
623d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    actualSize = partitionAllocGetSize(ptr);
624d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(predictedSize, actualSize);
625d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(requestedSize, actualSize);
626d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
627d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
628d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Allocate a size that is a system page smaller than a bucket. GetSize()
629d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // should return a larger size than we asked for now.
630d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    requestedSize = (256 * 1024) - WTF::kSystemPageSize - kExtraAllocSize;
631d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSize);
632d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
633d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(ptr);
634d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    actualSize = partitionAllocGetSize(ptr);
635d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(predictedSize, actualSize);
636d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(requestedSize + WTF::kSystemPageSize, actualSize);
637d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Check that we can write at the end of the reported size too.
638d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    char* charPtr = reinterpret_cast<char*>(ptr);
639d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    *(charPtr + (actualSize - 1)) = 'A';
640d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
641d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
642d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Allocate something very large, and uneven.
643d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    requestedSize = 512 * 1024 * 1024 - 1;
644d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSize);
645d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
646d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(ptr);
647d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    actualSize = partitionAllocGetSize(ptr);
648d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(predictedSize, actualSize);
649d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_LT(requestedSize, actualSize);
650d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
651d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
652d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Too large allocation.
653d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    requestedSize = INT_MAX;
654d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSize);
655d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(requestedSize, predictedSize);
656d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
657d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    TestShutdown();
658d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
659d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
66009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// Test the realloc() contract.
661f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, Realloc)
66209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
66309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestSetup();
66409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
66509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // realloc(0, size) should be equivalent to malloc().
66609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr = partitionReallocGeneric(genericAllocator.root(), 0, kTestAllocSize);
66709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    memset(ptr, 'A', kTestAllocSize);
66809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
66909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // realloc(ptr, 0) should be equivalent to free().
67009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, 0);
67109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, ptr2);
67209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(WTF::partitionCookieFreePointerAdjust(ptr), page->freelistHead);
67309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
674d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Test that growing an allocation with realloc() copies everything from the
675d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // old allocation.
676d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    size_t size = WTF::kSystemPageSize - kExtraAllocSize;
677d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(size, partitionAllocActualSize(genericAllocator.root(), size));
678d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), size);
679d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    memset(ptr, 'A', size);
680d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, size + 1);
681d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_NE(ptr, ptr2);
682d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    char* charPtr2 = static_cast<char*>(ptr2);
683d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ('A', charPtr2[0]);
684d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ('A', charPtr2[size - 1]);
685197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if ENABLE(ASSERT)
686d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(WTF::kUninitializedByte, static_cast<unsigned char>(charPtr2[size]));
687d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#endif
688d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
689d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Test that shrinking an allocation with realloc() also copies everything
690d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // from the old allocation.
691d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - 1);
692d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_NE(ptr2, ptr);
693d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    char* charPtr = static_cast<char*>(ptr);
694d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ('A', charPtr[0]);
695d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ('A', charPtr[size - 2]);
696197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if ENABLE(ASSERT)
697d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(WTF::kUninitializedByte, static_cast<unsigned char>(charPtr[size - 1]));
698d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#endif
699d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
700d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
701d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
702f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    // Test that shrinking a direct mapped allocation happens in-place.
703d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    size = WTF::kGenericMaxBucketed + 16 * WTF::kSystemPageSize;
704d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), size);
705d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    size_t actualSize = partitionAllocGetSize(ptr);
706f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericMaxBucketed + 8 * WTF::kSystemPageSize);
707d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(ptr, ptr2);
708f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    EXPECT_EQ(actualSize - 8 * WTF::kSystemPageSize, partitionAllocGetSize(ptr2));
709d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
710d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Test that a previously in-place shrunk direct mapped allocation can be
711d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // expanded up again within its original size.
712d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - WTF::kSystemPageSize);
713d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(ptr2, ptr);
714d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(actualSize - WTF::kSystemPageSize, partitionAllocGetSize(ptr));
715d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
716f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    // Test that a direct mapped allocation is performed not in-place when the
717f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    // new size is small enough.
718f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kSystemPageSize);
719f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    EXPECT_NE(ptr, ptr2);
720f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu
721f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    partitionFreeGeneric(genericAllocator.root(), ptr2);
722d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
7231fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    TestShutdown();
7241fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch}
7251fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch
72606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)// Tests the handing out of freelists for partial pages.
727f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, PartialPageFreelists)
72806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles){
72906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    TestSetup();
73006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
731f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize;
732a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(WTF::kSystemPageSize - WTF::kAllocationGranularity, bigSize + kExtraAllocSize);
733f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    size_t bucketIdx = (bigSize + kExtraAllocSize) >> WTF::kBucketShift;
73406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
735a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(0, bucket->freePagesHead);
73606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
73706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    void* ptr = partitionAlloc(allocator.root(), bigSize);
73806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_TRUE(ptr);
73906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
740a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
74109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (bigSize + kExtraAllocSize);
74209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(4u, totalSlots);
74309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // The freelist should have one entry, because we were able to exactly fit
74409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // one object slot and one freelist pointer (the null that the head points
74509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // to) into a system page.
74609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(page->freelistHead);
74706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_EQ(1, page->numAllocatedSlots);
74809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(2, page->numUnprovisionedSlots);
74906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
75006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    void* ptr2 = partitionAlloc(allocator.root(), bigSize);
75106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_TRUE(ptr2);
75209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_FALSE(page->freelistHead);
75306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_EQ(2, page->numAllocatedSlots);
75409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(2, page->numUnprovisionedSlots);
75506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
75606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    void* ptr3 = partitionAlloc(allocator.root(), bigSize);
75706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_TRUE(ptr3);
75809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(page->freelistHead);
75906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_EQ(3, page->numAllocatedSlots);
76009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page->numUnprovisionedSlots);
76106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
76206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    void* ptr4 = partitionAlloc(allocator.root(), bigSize);
76306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_TRUE(ptr4);
76409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_FALSE(page->freelistHead);
765a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(4, page->numAllocatedSlots);
76609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page->numUnprovisionedSlots);
767a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
768a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    void* ptr5 = partitionAlloc(allocator.root(), bigSize);
769a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_TRUE(ptr5);
770a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
771a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page2 = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr5));
77206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_EQ(1, page2->numAllocatedSlots);
77306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
7741e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Churn things a little whilst there's a partial page freelist.
7751e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    partitionFree(ptr);
7761e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    ptr = partitionAlloc(allocator.root(), bigSize);
777a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    void* ptr6 = partitionAlloc(allocator.root(), bigSize);
7781e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
77906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    partitionFree(ptr);
78006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    partitionFree(ptr2);
78106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    partitionFree(ptr3);
78206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    partitionFree(ptr4);
7831e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    partitionFree(ptr5);
784a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    partitionFree(ptr6);
78509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_NE(-1, page->freeCacheIndex);
78609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_NE(-1, page2->freeCacheIndex);
78709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(page2->freelistHead);
788bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    EXPECT_EQ(0, page2->numAllocatedSlots);
78906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
790a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    // And test a couple of sizes that do not cross kSystemPageSize with a single allocation.
79109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t mediumSize = (WTF::kSystemPageSize / 2) - kExtraAllocSize;
792f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    bucketIdx = (mediumSize + kExtraAllocSize) >> WTF::kBucketShift;
79306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    bucket = &allocator.root()->buckets()[bucketIdx];
794a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(0, bucket->freePagesHead);
79506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
79606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    ptr = partitionAlloc(allocator.root(), mediumSize);
79706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_TRUE(ptr);
798a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
79906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_EQ(1, page->numAllocatedSlots);
80009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (mediumSize + kExtraAllocSize);
801a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    size_t firstPageSlots = WTF::kSystemPageSize / (mediumSize + kExtraAllocSize);
80209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(2u, firstPageSlots);
803a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
80406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
80506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    partitionFree(ptr);
80606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
80709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t smallSize = (WTF::kSystemPageSize / 4) - kExtraAllocSize;
808f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    bucketIdx = (smallSize + kExtraAllocSize) >> WTF::kBucketShift;
80906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    bucket = &allocator.root()->buckets()[bucketIdx];
810a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(0, bucket->freePagesHead);
81106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
81206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    ptr = partitionAlloc(allocator.root(), smallSize);
81306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_TRUE(ptr);
814a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
81506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_EQ(1, page->numAllocatedSlots);
81609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (smallSize + kExtraAllocSize);
817a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    firstPageSlots = WTF::kSystemPageSize / (smallSize + kExtraAllocSize);
81806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
81906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
82006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    partitionFree(ptr);
82109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(page->freelistHead);
822bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    EXPECT_EQ(0, page->numAllocatedSlots);
82306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
82409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t verySmallSize = 32 - kExtraAllocSize;
825f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    bucketIdx = (verySmallSize + kExtraAllocSize) >> WTF::kBucketShift;
82606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    bucket = &allocator.root()->buckets()[bucketIdx];
827a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(0, bucket->freePagesHead);
82806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
82906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    ptr = partitionAlloc(allocator.root(), verySmallSize);
83006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_TRUE(ptr);
831a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
83206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_EQ(1, page->numAllocatedSlots);
83309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (verySmallSize + kExtraAllocSize);
834a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    firstPageSlots = WTF::kSystemPageSize / (verySmallSize + kExtraAllocSize);
83506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
83606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
83706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    partitionFree(ptr);
83809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(page->freelistHead);
839bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    EXPECT_EQ(0, page->numAllocatedSlots);
8401e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
84109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // And try an allocation size (against the generic allocator) that is
84209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // larger than a system page.
84309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t pageAndAHalfSize = (WTF::kSystemPageSize + (WTF::kSystemPageSize / 2)) - kExtraAllocSize;
84409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), pageAndAHalfSize);
84509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr);
84609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
84709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(1, page->numAllocatedSlots);
84809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(page->freelistHead);
84909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (pageAndAHalfSize + kExtraAllocSize);
85009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(totalSlots - 2, page->numUnprovisionedSlots);
85109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
85209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
85309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // And then make sure than exactly the page size only faults one page.
85409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t pageSize = WTF::kSystemPageSize - kExtraAllocSize;
85509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), pageSize);
85609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr);
85709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
85809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(1, page->numAllocatedSlots);
85909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_FALSE(page->freelistHead);
86009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (pageSize + kExtraAllocSize);
86109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(totalSlots - 1, page->numUnprovisionedSlots);
86209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
86309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
8641e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    TestShutdown();
8651e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)}
8661e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
8671e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)// Test some of the fragmentation-resistant properties of the allocator.
868f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, PageRefilling)
8691e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){
8701e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    TestSetup();
871f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
8721e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
8731e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Grab two full pages and a non-full page.
874a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page1 = GetFullPage(kTestAllocSize);
875a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize);
8761e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    void* ptr = partitionAlloc(allocator.root(), kTestAllocSize);
8771e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    EXPECT_TRUE(ptr);
878a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_NE(page1, bucket->activePagesHead);
879a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_NE(page2, bucket->activePagesHead);
880a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
8811e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    EXPECT_EQ(1, page->numAllocatedSlots);
8821e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
8831e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Work out a pointer into page2 and free it; and then page1 and free it.
884a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    char* ptr2 = reinterpret_cast<char*>(WTF::partitionPageToPointer(page1)) + kPointerOffset;
8851e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    partitionFree(ptr2);
886a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    ptr2 = reinterpret_cast<char*>(WTF::partitionPageToPointer(page2)) + kPointerOffset;
8871e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    partitionFree(ptr2);
8881e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
8891e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // If we perform two allocations from the same bucket now, we expect to
8901e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // refill both the nearly full pages.
8911e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    (void) partitionAlloc(allocator.root(), kTestAllocSize);
8921e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    (void) partitionAlloc(allocator.root(), kTestAllocSize);
8931e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    EXPECT_EQ(1, page->numAllocatedSlots);
8941e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
895f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page2);
896f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page1);
8971e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    partitionFree(ptr);
89806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
89906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    TestShutdown();
90006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
90106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
902f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)// Basic tests to ensure that allocations work for partial page buckets.
903f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, PartialPages)
904f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles){
905f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    TestSetup();
906f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)
907f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    // Find a size that is backed by a partial partition page.
908f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    size_t size = sizeof(void*);
909f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    WTF::PartitionBucket* bucket = 0;
910f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    while (size < kTestMaxAllocation) {
911f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)        bucket = &allocator.root()->buckets()[size >> WTF::kBucketShift];
91209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (bucket->numSystemPagesPerSlotSpan % WTF::kNumSystemPagesPerPartitionPage)
913f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)            break;
914f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)        size += sizeof(void*);
915f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    }
916f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    EXPECT_LT(size, kTestMaxAllocation);
917f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)
918a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page1 = GetFullPage(size);
919a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* page2 = GetFullPage(size);
920f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page2);
921f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(page1);
922f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)
923f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    TestShutdown();
924f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)}
925f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)
926521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// Test correct handling if our mapping collides with another.
927f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, MappingCollision)
928521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles){
929521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    TestSetup();
930a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    // The -2 is because the first and last partition pages in a super page are
931a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    // guard pages.
932a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    size_t numPartitionPagesNeeded = WTF::kNumPartitionPagesPerSuperPage - 2;
933a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    OwnPtr<WTF::PartitionPage*[]> firstSuperPagePages = adoptArrayPtr(new WTF::PartitionPage*[numPartitionPagesNeeded]);
934a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    OwnPtr<WTF::PartitionPage*[]> secondSuperPagePages = adoptArrayPtr(new WTF::PartitionPage*[numPartitionPagesNeeded]);
935521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
9361e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    size_t i;
9371e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    for (i = 0; i < numPartitionPagesNeeded; ++i)
9381e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        firstSuperPagePages[i] = GetFullPage(kTestAllocSize);
9391e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
940a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    char* pageBase = reinterpret_cast<char*>(WTF::partitionPageToPointer(firstSuperPagePages[0]));
941a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(WTF::kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & WTF::kSuperPageOffsetMask);
942a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    pageBase -= WTF::kPartitionPageSize;
943521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // Map a single system page either side of the mapping for our allocations,
944521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // with the goal of tripping up alignment of the next mapping.
945a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    void* map1 = WTF::allocPages(pageBase - WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity);
946a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_TRUE(map1);
947a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    void* map2 = WTF::allocPages(pageBase + WTF::kSuperPageSize, WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity);
948a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_TRUE(map2);
949a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::setSystemPagesInaccessible(map1, WTF::kPageAllocationGranularity);
950a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::setSystemPagesInaccessible(map2, WTF::kPageAllocationGranularity);
951521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
9521e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    for (i = 0; i < numPartitionPagesNeeded; ++i)
9531e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        secondSuperPagePages[i] = GetFullPage(kTestAllocSize);
954521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
955a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::freePages(map1, WTF::kPageAllocationGranularity);
956a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::freePages(map2, WTF::kPageAllocationGranularity);
957521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
958a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    pageBase = reinterpret_cast<char*>(partitionPageToPointer(secondSuperPagePages[0]));
959a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(WTF::kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & WTF::kSuperPageOffsetMask);
960a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    pageBase -= WTF::kPartitionPageSize;
9611e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // Map a single system page either side of the mapping for our allocations,
9621e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // with the goal of tripping up alignment of the next mapping.
963a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    map1 = WTF::allocPages(pageBase - WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity);
964a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_TRUE(map1);
965a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    map2 = WTF::allocPages(pageBase + WTF::kSuperPageSize, WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity);
966a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_TRUE(map2);
967a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::setSystemPagesInaccessible(map1, WTF::kPageAllocationGranularity);
968a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::setSystemPagesInaccessible(map2, WTF::kPageAllocationGranularity);
9691e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
970a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::PartitionPage* pageInThirdSuperPage = GetFullPage(kTestAllocSize);
971a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::freePages(map1, WTF::kPageAllocationGranularity);
972a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    WTF::freePages(map2, WTF::kPageAllocationGranularity);
9731e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
974a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(partitionPageToPointer(pageInThirdSuperPage)) & WTF::kPartitionPageOffsetMask);
9751e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
9761e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    // And make sure we really did get a page in a new superpage.
977a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(firstSuperPagePages[0])) & WTF::kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer(pageInThirdSuperPage)) & WTF::kSuperPageBaseMask);
978a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(secondSuperPagePages[0])) & WTF::kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer(pageInThirdSuperPage)) & WTF::kSuperPageBaseMask);
9791e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
980f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)    FreeFullPage(pageInThirdSuperPage);
9811e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    for (i = 0; i < numPartitionPagesNeeded; ++i) {
982f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)        FreeFullPage(firstSuperPagePages[i]);
983f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)        FreeFullPage(secondSuperPagePages[i]);
9841e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    }
9851e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
986521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    TestShutdown();
987521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)}
988521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
98909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// Tests that pages in the free page cache do get freed as appropriate.
990f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, FreeCache)
99109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
99209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestSetup();
99309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
9945d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    EXPECT_EQ(0U, allocator.root()->totalSizeOfCommittedPages);
9955d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)
99609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize;
99709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t bucketIdx = (bigSize + kExtraAllocSize) >> WTF::kBucketShift;
99809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
99909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
100009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr = partitionAlloc(allocator.root(), bigSize);
100109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr);
100209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
100309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, bucket->freePagesHead);
100409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(1, page->numAllocatedSlots);
10055d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    EXPECT_EQ(WTF::kPartitionPageSize, allocator.root()->totalSizeOfCommittedPages);
100609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFree(ptr);
100709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page->numAllocatedSlots);
100809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_NE(-1, page->freeCacheIndex);
100909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(page->freelistHead);
101009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
101109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    CycleFreeCache(kTestAllocSize);
101209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
101309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Flushing the cache should have really freed the unused page.
101409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_FALSE(page->freelistHead);
101509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(-1, page->freeCacheIndex);
101609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_EQ(0, page->numAllocatedSlots);
10175d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    WTF::PartitionBucket* cycleFreeCacheBucket = &allocator.root()->buckets()[kTestBucketIndex];
10185d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    EXPECT_EQ(cycleFreeCacheBucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize, allocator.root()->totalSizeOfCommittedPages);
101909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
102009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Check that an allocation works ok whilst in this state (a free'd page
102109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // as the active pages head).
102209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ptr = partitionAlloc(allocator.root(), bigSize);
102309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_FALSE(bucket->freePagesHead);
102409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFree(ptr);
102509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
102609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Also check that a page that is bouncing immediately between empty and
102709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // used does not get freed.
102809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    for (size_t i = 0; i < WTF::kMaxFreeableSpans * 2; ++i) {
102909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        ptr = partitionAlloc(allocator.root(), bigSize);
103009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        EXPECT_TRUE(page->freelistHead);
103109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        partitionFree(ptr);
103209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        EXPECT_TRUE(page->freelistHead);
103309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
10345d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    EXPECT_EQ(WTF::kPartitionPageSize, allocator.root()->totalSizeOfCommittedPages);
103509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestShutdown();
103609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
103709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
1038d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)// Tests for a bug we had with losing references to free pages.
1039f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, LostFreePagesBug)
1040d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){
1041d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    TestSetup();
1042d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1043d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    size_t size = WTF::kPartitionPageSize - kExtraAllocSize;
1044d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1045d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
1046d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(ptr);
1047d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
1048d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(ptr2);
1049d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1050d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
1051d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    WTF::PartitionPage* page2 = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr2));
1052d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    WTF::PartitionBucket* bucket = page->bucket;
1053d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1054d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(0, bucket->freePagesHead);
1055d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(-1, page->numAllocatedSlots);
1056d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(1, page2->numAllocatedSlots);
1057d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1058d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
1059d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr2);
1060d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1061d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(0, bucket->freePagesHead);
1062d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(0, page->numAllocatedSlots);
1063d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_EQ(0, page2->numAllocatedSlots);
1064d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(page->freelistHead);
1065d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(page2->freelistHead);
1066d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1067d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    CycleGenericFreeCache(kTestAllocSize);
1068d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1069d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_FALSE(page->freelistHead);
1070d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_FALSE(page2->freelistHead);
1071d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1072d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_FALSE(bucket->freePagesHead);
1073d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(bucket->activePagesHead);
1074d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(bucket->activePagesHead->nextPage);
1075d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1076d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // At this moment, we have two freed pages, on the freelist.
1077d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1078d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), size);
1079d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(ptr);
1080d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
1081d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1082d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(bucket->activePagesHead);
1083d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(bucket->freePagesHead);
1084d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1085d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    CycleGenericFreeCache(kTestAllocSize);
1086d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1087d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // We're now set up to trigger the bug by scanning over the active pages
1088d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // list, where the current active page is freed, and there exists at least
1089d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // one freed page in the free pages list.
1090d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ptr = partitionAllocGeneric(genericAllocator.root(), size);
1091d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(ptr);
1092d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
1093d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1094d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(bucket->activePagesHead);
1095d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    EXPECT_TRUE(bucket->freePagesHead);
1096d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1097d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    TestShutdown();
1098d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
1099d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1100d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#if !OS(ANDROID)
1101d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
110209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// Make sure that malloc(-1) dies.
110309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// In the past, we had an integer overflow that would alias malloc(-1) to
110409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// malloc(0), which is not good.
1105f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocDeathTest, LargeAllocs)
110609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
110709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestSetup();
110809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // Largest alloc.
110909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_DEATH(partitionAllocGeneric(genericAllocator.root(), static_cast<size_t>(-1)), "");
111009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // And the smallest allocation we expect to die.
111109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_DEATH(partitionAllocGeneric(genericAllocator.root(), static_cast<size_t>(INT_MAX) + 1), "");
111209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
111309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestShutdown();
111409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
111509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
111609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// Check that our immediate double-free detection works.
1117f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocDeathTest, ImmediateDoubleFree)
111809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
111909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestSetup();
112009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
112109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
112209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr);
112309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
112409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
112509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), ptr), "");
112609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
112709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestShutdown();
112809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
112909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
113009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// Check that our refcount-based double-free detection works.
1131f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocDeathTest, RefcountDoubleFree)
113209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
113309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestSetup();
113409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
113509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
113609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr);
113709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr2 = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
113809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr2);
113909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
114009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr2);
114109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // This is not an immediate double-free so our immediate detection won't
114209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // fire. However, it does take the "refcount" of the partition page to -1,
114309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // which is illegal and should be trapped.
114409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), ptr), "");
114509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
114609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestShutdown();
114709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
114809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
114909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// Check that guard pages are present where expected.
1150f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocDeathTest, GuardPages)
115109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
115209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestSetup();
115309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
115409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // This large size will result in a direct mapped allocation with guard
115509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // pages at either end.
115609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    size_t size = (WTF::kGenericMaxBucketed + WTF::kSystemPageSize) - kExtraAllocSize;
115709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
115809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_TRUE(ptr);
115909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    char* charPtr = reinterpret_cast<char*>(ptr) - kPointerOffset;
116009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
116109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_DEATH(*(charPtr - 1) = 'A', "");
116209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EXPECT_DEATH(*(charPtr + size + kExtraAllocSize) = 'A', "");
116309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
116409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    partitionFreeGeneric(genericAllocator.root(), ptr);
116509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
116609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    TestShutdown();
116709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
116809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
1169d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#endif // !OS(ANDROID)
1170d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1171a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)// Tests that the countLeadingZeros() functions work to our satisfaction.
1172a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)// It doesn't seem worth the overhead of a whole new file for these tests, so
1173a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)// we'll put them here since partitionAllocGeneric will depend heavily on these
1174a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)// functions working correctly.
1175f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo LiuTEST(PartitionAllocTest, CLZWorks)
1176a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles){
1177197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(32u, WTF::countLeadingZeros32(0u));
1178197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(31u, WTF::countLeadingZeros32(1u));
1179197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(1u, WTF::countLeadingZeros32(1u << 30));
1180197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(0u, WTF::countLeadingZeros32(1u << 31));
1181a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
1182a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#if CPU(64BIT)
1183a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(64u, WTF::countLeadingZerosSizet(0ull));
1184a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(63u, WTF::countLeadingZerosSizet(1ull));
1185a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(32u, WTF::countLeadingZerosSizet(1ull << 31));
1186a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(1u, WTF::countLeadingZerosSizet(1ull << 62));
1187a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    EXPECT_EQ(0u, WTF::countLeadingZerosSizet(1ull << 63));
1188a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#else
1189197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(32u, WTF::countLeadingZerosSizet(0u));
1190197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(31u, WTF::countLeadingZerosSizet(1u));
1191197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(1u, WTF::countLeadingZerosSizet(1u << 30));
1192197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(0u, WTF::countLeadingZerosSizet(1u << 31));
1193a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#endif
1194a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)}
1195521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
11965267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)} // namespace
11975267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
1198591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch#endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
1199