xref: /aosp_15_r20/external/skia/tests/ArenaAllocTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/SkTypes.h"
9 #include "src/base/SkArenaAlloc.h"
10 #include "tests/Test.h"
11 
12 #include <cstddef>
13 #include <cstdint>
14 #include <initializer_list>
15 #include <limits>
16 #include <memory>
17 #include <new>
18 
DEF_TEST(ArenaAlloc,r)19 DEF_TEST(ArenaAlloc, r) {
20     static int created = 0,
21                destroyed = 0;
22 
23     struct Foo {
24         Foo() : x(-2), y(-3.0f) { created++; }
25         Foo(int X, float Y) : x(X), y(Y) { created++; }
26         ~Foo() { destroyed++; }
27         int x;
28         float y;
29     };
30 
31     struct alignas(8) OddAlignment {
32         char buf[10];
33     };
34 
35     // Check construction/destruction counts from SkArenaAlloc.
36     created = 0;
37     destroyed = 0;
38     {
39         SkArenaAlloc arena{0};
40         REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
41         Foo* foo = arena.make<Foo>(3, 4.0f);
42         REPORTER_ASSERT(r, foo->x == 3);
43         REPORTER_ASSERT(r, foo->y == 4.0f);
44         REPORTER_ASSERT(r, created == 1);
45         REPORTER_ASSERT(r, destroyed == 0);
46         arena.makeArrayDefault<int>(10);
47         int* zeroed = arena.makeArray<int>(10);
48         for (int i = 0; i < 10; i++) {
49             REPORTER_ASSERT(r, zeroed[i] == 0);
50         }
51         Foo* fooArray = arena.makeArrayDefault<Foo>(10);
52         REPORTER_ASSERT(r, fooArray[3].x == -2);
53         REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
54         REPORTER_ASSERT(r, created == 11);
55         REPORTER_ASSERT(r, destroyed == 0);
56         arena.make<OddAlignment>();
57     }
58     REPORTER_ASSERT(r, created == 11);
59     REPORTER_ASSERT(r, destroyed == 11);
60 
61     // Check construction/destruction counts from SkSTArenaAlloc.
62     created = 0;
63     destroyed = 0;
64     {
65         SkSTArenaAlloc<64> arena;
66         REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
67         Foo* foo = arena.make<Foo>(3, 4.0f);
68         REPORTER_ASSERT(r, foo->x == 3);
69         REPORTER_ASSERT(r, foo->y == 4.0f);
70         REPORTER_ASSERT(r, created == 1);
71         REPORTER_ASSERT(r, destroyed == 0);
72         arena.makeArrayDefault<int>(10);
73         int* zeroed = arena.makeArray<int>(10);
74         for (int i = 0; i < 10; i++) {
75             REPORTER_ASSERT(r, zeroed[i] == 0);
76         }
77         Foo* fooArray = arena.makeArrayDefault<Foo>(10);
78         REPORTER_ASSERT(r, fooArray[3].x == -2);
79         REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
80         REPORTER_ASSERT(r, created == 11);
81         REPORTER_ASSERT(r, destroyed == 0);
82         arena.make<OddAlignment>();
83     }
84     REPORTER_ASSERT(r, created == 11);
85     REPORTER_ASSERT(r, destroyed == 11);
86 
87     // Check construction/destruction counts from SkArenaAlloc when passed an initial block.
88     created = 0;
89     destroyed = 0;
90     {
91         std::unique_ptr<char[]> block{new char[1024]};
92         SkArenaAlloc arena{block.get(), 1024, 0};
93         REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
94         Foo* foo = arena.make<Foo>(3, 4.0f);
95         REPORTER_ASSERT(r, foo->x == 3);
96         REPORTER_ASSERT(r, foo->y == 4.0f);
97         REPORTER_ASSERT(r, created == 1);
98         REPORTER_ASSERT(r, destroyed == 0);
99         arena.makeArrayDefault<int>(10);
100         int* zeroed = arena.makeArray<int>(10);
101         for (int i = 0; i < 10; i++) {
102             REPORTER_ASSERT(r, zeroed[i] == 0);
103         }
104         Foo* fooArray = arena.makeArrayDefault<Foo>(10);
105         REPORTER_ASSERT(r, fooArray[3].x == -2);
106         REPORTER_ASSERT(r, fooArray[4].y == -3.0f);
107         REPORTER_ASSERT(r, created == 11);
108         REPORTER_ASSERT(r, destroyed == 0);
109         arena.make<OddAlignment>();
110     }
111     REPORTER_ASSERT(r, created == 11);
112     REPORTER_ASSERT(r, destroyed == 11);
113 }
114 
DEF_TEST(ArenaAllocReset,r)115 DEF_TEST(ArenaAllocReset, r) {
116     SkSTArenaAllocWithReset<64> arena;
117     arena.makeArrayDefault<char>(256);
118     arena.reset();
119     arena.reset();
120 }
121 
DEF_TEST(ArenaAllocIsEmpty,r)122 DEF_TEST(ArenaAllocIsEmpty, r) {
123     char storage[1000];
124     for (int arenaSize : {1, 2, 3, 10, 100, 1000}) {
125         for (int alloc1Size : {1, 10, 100, 1000}) {
126             for (int alloc2Size : {1, 10, 100, 1000}) {
127                 SkArenaAllocWithReset arena(storage, arenaSize, 1000);
128                 REPORTER_ASSERT(r, arena.isEmpty());
129 
130                 [[maybe_unused]] char* alloc1 = arena.makeArray<char>(alloc1Size);
131                 REPORTER_ASSERT(r, !arena.isEmpty());
132 
133                 [[maybe_unused]] char* alloc2 = arena.makeArray<char>(alloc2Size);
134                 REPORTER_ASSERT(r, !arena.isEmpty());
135 
136                 arena.reset();
137                 REPORTER_ASSERT(r, arena.isEmpty());
138             }
139         }
140     }
141 }
142 
DEF_TEST(ArenaAllocWithMultipleBlocks,r)143 DEF_TEST(ArenaAllocWithMultipleBlocks, r) {
144     // Make sure that multiple blocks are handled correctly.
145     static int created = 0,
146                destroyed = 0;
147     {
148         struct Node {
149             Node(Node* n) : next(n) { created++; }
150             ~Node() { destroyed++; }
151             Node *next;
152             char filler[64];
153         };
154 
155         SkSTArenaAlloc<64> arena;
156         Node* current = nullptr;
157         for (int i = 0; i < 128; i++) {
158             current = arena.make<Node>(current);
159         }
160     }
161     REPORTER_ASSERT(r, created == 128);
162     REPORTER_ASSERT(r, destroyed == 128);
163 }
164 
DEF_TEST(ArenaAllocDestructionOrder,r)165 DEF_TEST(ArenaAllocDestructionOrder, r) {
166     // Make sure that objects and blocks are destroyed in the correct order. If they are not,
167     // then there will be a use after free error in asan.
168     static int created = 0,
169                destroyed = 0;
170     {
171         struct Node {
172             Node(Node* n) : next(n) { created++; }
173             ~Node() {
174                 destroyed++;
175                 if (next) {
176                     next->~Node();
177                 }
178             }
179             Node *next;
180         };
181 
182         SkSTArenaAlloc<64> arena;
183         Node* current = nullptr;
184         for (int i = 0; i < 128; i++) {
185             uint64_t* temp = arena.makeArrayDefault<uint64_t>(sizeof(Node) / sizeof(Node*));
186             current = new (temp)Node(current);
187         }
188         current->~Node();
189     }
190     REPORTER_ASSERT(r, created == 128);
191     REPORTER_ASSERT(r, destroyed == 128);
192 
193     {
194         SkSTArenaAlloc<64> arena;
195         auto a = arena.makeInitializedArray<int>(8, [](size_t i ) { return i; });
196         for (size_t i = 0; i < 8; i++) {
197             REPORTER_ASSERT(r, a[i] == (int)i);
198         }
199     }
200 }
201 
DEF_TEST(ArenaAllocUnusualAlignment,r)202 DEF_TEST(ArenaAllocUnusualAlignment, r) {
203     SkArenaAlloc arena(4096);
204     // Move to a 1 character boundary.
205     arena.make<char>();
206     // Allocate something with interesting alignment.
207     void* ptr = arena.makeBytesAlignedTo(4081, 8);
208     REPORTER_ASSERT(r, ((intptr_t)ptr & 7) == 0);
209 }
210 
DEF_TEST(SkFibBlockSizes,r)211 DEF_TEST(SkFibBlockSizes, r) {
212     {
213         SkFibBlockSizes<std::numeric_limits<uint32_t>::max()> fibs{1, 1};
214         uint32_t lastSize = 1;
215         for (int i = 0; i < 64; i++) {
216             uint32_t size = fibs.nextBlockSize();
217             REPORTER_ASSERT(r, lastSize <= size);
218             lastSize = size;
219         }
220         REPORTER_ASSERT(r, lastSize == 2971215073u);
221     }
222     {
223         SkFibBlockSizes<std::numeric_limits<uint32_t>::max()> fibs{0, 1024};
224         uint32_t lastSize = 1;
225         for (int i = 0; i < 64; i++) {
226             uint32_t size = fibs.nextBlockSize();
227             REPORTER_ASSERT(r, lastSize <= size);
228             lastSize = size;
229             REPORTER_ASSERT(r, lastSize <= std::numeric_limits<uint32_t>::max());
230         }
231         REPORTER_ASSERT(r, lastSize == 3524578u * 1024);
232     }
233 
234     {
235         SkFibBlockSizes<std::numeric_limits<uint32_t>::max() / 2> fibs{1024, 0};
236         uint32_t lastSize = 1;
237         for (int i = 0; i < 64; i++) {
238             uint32_t size = fibs.nextBlockSize();
239             REPORTER_ASSERT(r, lastSize <= size);
240             lastSize = size;
241             REPORTER_ASSERT(r, lastSize <= std::numeric_limits<uint32_t>::max() / 2);
242         }
243         REPORTER_ASSERT(r, lastSize == 1346269u * 1024);
244     }
245 }
246