1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkRefCnt.h"
9 #include "include/core/SkTypes.h"
10 #include "src/core/SkArenaAlloc.h"
11 #include "tests/Test.h"
12 
13 #include <memory>
14 #include <new>
15 #include <type_traits>
16 
DEF_TEST(ArenaAlloc,r)17 DEF_TEST(ArenaAlloc, r) {
18     static int created = 0,
19                destroyed = 0;
20 
21     struct Foo {
22         Foo() : x(-2), y(-3.0f) { created++; }
23         Foo(int X, float Y) : x(X), y(Y) { created++; }
24         ~Foo() { destroyed++; }
25         int x;
26         float y;
27     };
28 
29     struct alignas(8) OddAlignment {
30         char buf[10];
31     };
32 
33     created = 0;
34     destroyed = 0;
35     {
36         SkArenaAlloc arena{0};
37         REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
38         Foo* foo = arena.make<Foo>(3, 4.0f);
39         REPORTER_ASSERT(r, foo->x == 3);
40         REPORTER_ASSERT(r, foo->y == 4.0f);
41         REPORTER_ASSERT(r, created == 1);
42         REPORTER_ASSERT(r, destroyed == 0);
43         arena.makeArrayDefault<int>(10);
44         int* zeroed = arena.makeArray<int>(10);
45         for (int i = 0; i < 10; i++) {
46             REPORTER_ASSERT(r, zeroed[i] == 0);
47         }
48         Foo* fooArray = arena.makeArrayDefault<Foo>(10);
49         REPORTER_ASSERT(r, fooArray[3].x == -2);
50         REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
51         REPORTER_ASSERT(r, created == 11);
52         REPORTER_ASSERT(r, destroyed == 0);
53         arena.make<OddAlignment>();
54     }
55     REPORTER_ASSERT(r, created == 11);
56     REPORTER_ASSERT(r, destroyed == 11);
57 
58     created = 0;
59     destroyed = 0;
60     {
61         SkSTArenaAlloc<64> arena;
62         REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
63         Foo* foo = arena.make<Foo>(3, 4.0f);
64         REPORTER_ASSERT(r, foo->x == 3);
65         REPORTER_ASSERT(r, foo->y == 4.0f);
66         REPORTER_ASSERT(r, created == 1);
67         REPORTER_ASSERT(r, destroyed == 0);
68         arena.makeArrayDefault<int>(10);
69         int* zeroed = arena.makeArray<int>(10);
70         for (int i = 0; i < 10; i++) {
71             REPORTER_ASSERT(r, zeroed[i] == 0);
72         }
73         Foo* fooArray = arena.makeArrayDefault<Foo>(10);
74         REPORTER_ASSERT(r, fooArray[3].x == -2);
75         REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
76         REPORTER_ASSERT(r, created == 11);
77         REPORTER_ASSERT(r, destroyed == 0);
78         arena.make<OddAlignment>();
79     }
80     REPORTER_ASSERT(r, created == 11);
81     REPORTER_ASSERT(r, destroyed == 11);
82 
83     created = 0;
84     destroyed = 0;
85     {
86         std::unique_ptr<char[]> block{new char[1024]};
87         SkArenaAlloc arena{block.get(), 1024, 0};
88         REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
89         Foo* foo = arena.make<Foo>(3, 4.0f);
90         REPORTER_ASSERT(r, foo->x == 3);
91         REPORTER_ASSERT(r, foo->y == 4.0f);
92         REPORTER_ASSERT(r, created == 1);
93         REPORTER_ASSERT(r, destroyed == 0);
94         arena.makeArrayDefault<int>(10);
95         int* zeroed = arena.makeArray<int>(10);
96         for (int i = 0; i < 10; i++) {
97             REPORTER_ASSERT(r, zeroed[i] == 0);
98         }
99         Foo* fooArray = arena.makeArrayDefault<Foo>(10);
100         REPORTER_ASSERT(r, fooArray[3].x == -2);
101         REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
102         REPORTER_ASSERT(r, created == 11);
103         REPORTER_ASSERT(r, destroyed == 0);
104         arena.make<OddAlignment>();
105     }
106     REPORTER_ASSERT(r, created == 11);
107     REPORTER_ASSERT(r, destroyed == 11);
108 
109     {
110         SkSTArenaAllocWithReset<64> arena;
111         arena.makeArrayDefault<char>(256);
112         arena.reset();
113         arena.reset();
114     }
115 
116     // Make sure that multiple blocks are handled correctly.
117     created = 0;
118     destroyed = 0;
119     {
120         struct Node {
121             Node(Node* n) : next(n) { created++; }
122             ~Node() { destroyed++; }
123             Node *next;
124             char filler[64];
125         };
126 
127         SkSTArenaAlloc<64> arena;
128         Node* current = nullptr;
129         for (int i = 0; i < 128; i++) {
130             current = arena.make<Node>(current);
131         }
132     }
133     REPORTER_ASSERT(r, created == 128);
134     REPORTER_ASSERT(r, destroyed == 128);
135 
136     // Make sure that objects and blocks are destroyed in the correct order. If they are not,
137     // then there will be a use after free error in asan.
138     created = 0;
139     destroyed = 0;
140     {
141         struct Node {
142             Node(Node* n) : next(n) { created++; }
143             ~Node() {
144                 destroyed++;
145                 if (next) {
146                     next->~Node();
147                 }
148             }
149             Node *next;
150         };
151 
152         SkSTArenaAlloc<64> arena;
153         Node* current = nullptr;
154         for (int i = 0; i < 128; i++) {
155             uint64_t* temp = arena.makeArrayDefault<uint64_t>(sizeof(Node) / sizeof(Node*));
156             current = new (temp)Node(current);
157         }
158         current->~Node();
159     }
160     REPORTER_ASSERT(r, created == 128);
161     REPORTER_ASSERT(r, destroyed == 128);
162 
163     {
164         SkSTArenaAlloc<64> arena;
165         auto a = arena.makeInitializedArray<int>(8, [](size_t i ) { return i; });
166         for (size_t i = 0; i < 8; i++) {
167             REPORTER_ASSERT(r, a[i] == (int)i);
168         }
169     }
170 
171     {
172         SkArenaAlloc arena(4096);
173         // Move to a 1 character boundary.
174         arena.make<char>();
175         // Allocate something with interesting alignment.
176         void* ptr = arena.makeBytesAlignedTo(4081, 8);
177         REPORTER_ASSERT(r, ((intptr_t)ptr & 7) == 0);
178     }
179 }
180 
DEF_TEST(SkFibBlockSizes,r)181 DEF_TEST(SkFibBlockSizes, r) {
182     {
183         SkFibBlockSizes<std::numeric_limits<uint32_t>::max()> fibs{1, 1};
184         uint32_t lastSize = 1;
185         for (int i = 0; i < 64; i++) {
186             uint32_t size = fibs.nextBlockSize();
187             REPORTER_ASSERT(r, lastSize <= size);
188             lastSize = size;
189         }
190         REPORTER_ASSERT(r, lastSize == 2971215073u);
191     }
192     {
193         SkFibBlockSizes<std::numeric_limits<uint32_t>::max()> fibs{0, 1024};
194         uint32_t lastSize = 1;
195         for (int i = 0; i < 64; i++) {
196             uint32_t size = fibs.nextBlockSize();
197             REPORTER_ASSERT(r, lastSize <= size);
198             lastSize = size;
199             REPORTER_ASSERT(r, lastSize <= std::numeric_limits<uint32_t>::max());
200         }
201         REPORTER_ASSERT(r, lastSize == 3524578u * 1024);
202     }
203 
204     {
205         SkFibBlockSizes<std::numeric_limits<uint32_t>::max() / 2> fibs{1024, 0};
206         uint32_t lastSize = 1;
207         for (int i = 0; i < 64; i++) {
208             uint32_t size = fibs.nextBlockSize();
209             REPORTER_ASSERT(r, lastSize <= size);
210             lastSize = size;
211             REPORTER_ASSERT(r, lastSize <= std::numeric_limits<uint32_t>::max() / 2);
212         }
213         REPORTER_ASSERT(r, lastSize == 1346269u * 1024);
214     }
215 }
216