1/*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "platform/PODFreeListArena.h"
28
29#include "platform/testing/ArenaTestHelpers.h"
30#include "wtf/FastMalloc.h"
31#include "wtf/RefPtr.h"
32
33#include <gtest/gtest.h>
34
35namespace blink {
36
37using ArenaTestHelpers::TrackedAllocator;
38
39namespace {
40
41// A couple of simple structs to allocate.
42struct TestClass1 {
43    TestClass1()
44        : x(0), y(0), z(0), w(1) { }
45
46    float x, y, z, w;
47};
48
49struct TestClass2 {
50    TestClass2()
51        : padding(0)
52    {
53        static int TestIds = 0;
54        id = TestIds++;
55    }
56    int id;
57    int padding;
58};
59
60} // anonymous namespace
61
62class PODFreeListArenaTest : public testing::Test {
63protected:
64    int getFreeListSize(const PassRefPtr<PODFreeListArena<TestClass1> > arena) const
65    {
66        return arena->getFreeListSizeForTesting();
67    }
68};
69
70// Make sure the arena can successfully allocate from more than one
71// region.
72TEST_F(PODFreeListArenaTest, CanAllocateFromMoreThanOneRegion)
73{
74    RefPtr<TrackedAllocator> allocator = TrackedAllocator::create();
75    RefPtr<PODFreeListArena<TestClass1> > arena = PODFreeListArena<TestClass1>::create(allocator);
76    int numIterations = 10 * PODArena::DefaultChunkSize / sizeof(TestClass1);
77    for (int i = 0; i < numIterations; ++i)
78        arena->allocateObject();
79    EXPECT_GT(allocator->numRegions(), 1);
80}
81
82// Make sure the arena frees all allocated regions during destruction.
83TEST_F(PODFreeListArenaTest, FreesAllAllocatedRegions)
84{
85    RefPtr<TrackedAllocator> allocator = TrackedAllocator::create();
86    {
87        RefPtr<PODFreeListArena<TestClass1> > arena = PODFreeListArena<TestClass1>::create(allocator);
88        for (int i = 0; i < 3; i++)
89            arena->allocateObject();
90        EXPECT_GT(allocator->numRegions(), 0);
91    }
92    EXPECT_TRUE(allocator->isEmpty());
93}
94
95// Make sure the arena runs constructors of the objects allocated within.
96TEST_F(PODFreeListArenaTest, RunsConstructorsOnNewObjects)
97{
98    RefPtr<PODFreeListArena<TestClass1> > arena = PODFreeListArena<TestClass1>::create();
99    for (int i = 0; i < 10000; i++) {
100        TestClass1* tc1 = arena->allocateObject();
101        EXPECT_EQ(0, tc1->x);
102        EXPECT_EQ(0, tc1->y);
103        EXPECT_EQ(0, tc1->z);
104        EXPECT_EQ(1, tc1->w);
105    }
106}
107
108// Make sure the arena runs constructors of the objects allocated within.
109TEST_F(PODFreeListArenaTest, RunsConstructorsOnReusedObjects)
110{
111    std::set<TestClass1*> objects;
112    RefPtr<PODFreeListArena<TestClass1> > arena = PODFreeListArena<TestClass1>::create();
113    for (int i = 0; i < 100; i++) {
114        TestClass1* tc1 = arena->allocateObject();
115        tc1->x = 100;
116        tc1->y = 101;
117        tc1->z = 102;
118        tc1->w = 103;
119
120        objects.insert(tc1);
121    }
122    for (std::set<TestClass1*>::iterator it = objects.begin(); it != objects.end(); ++it) {
123        arena->freeObject(*it);
124    }
125    for (int i = 0; i < 100; i++) {
126        TestClass1* cur = arena->allocateObject();
127        EXPECT_TRUE(objects.find(cur) != objects.end());
128        EXPECT_EQ(0, cur->x);
129        EXPECT_EQ(0, cur->y);
130        EXPECT_EQ(0, cur->z);
131        EXPECT_EQ(1, cur->w);
132
133        objects.erase(cur);
134    }
135}
136
137// Make sure freeObject puts the object in the free list.
138TEST_F(PODFreeListArenaTest, AddsFreedObjectsToFreedList)
139{
140    std::vector<TestClass1*> objects;
141    RefPtr<PODFreeListArena<TestClass1> > arena = PODFreeListArena<TestClass1>::create();
142    for (int i = 0; i < 100; i++) {
143        objects.push_back(arena->allocateObject());
144    }
145    for (std::vector<TestClass1*>::iterator it = objects.begin(); it != objects.end(); ++it) {
146        arena->freeObject(*it);
147    }
148    EXPECT_EQ(100, getFreeListSize(arena));
149}
150
151// Make sure allocations use previously freed memory.
152TEST_F(PODFreeListArenaTest, ReusesPreviouslyFreedObjects)
153{
154    std::set<TestClass2*> objects;
155    RefPtr<PODFreeListArena<TestClass2> > arena = PODFreeListArena<TestClass2>::create();
156    for (int i = 0; i < 100; i++) {
157        objects.insert(arena->allocateObject());
158    }
159    for (std::set<TestClass2*>::iterator it = objects.begin(); it != objects.end(); ++it) {
160        arena->freeObject(*it);
161    }
162    for (int i = 0; i < 100; i++) {
163        TestClass2* cur = arena->allocateObject();
164        EXPECT_TRUE(objects.find(cur) != objects.end());
165        EXPECT_TRUE(cur->id >= 100 && cur->id < 200);
166        objects.erase(cur);
167    }
168}
169
170} // namespace blink
171