| /* |
| * Copyright 2016 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/core/SkTypes.h" |
| #include "src/base/SkArenaAlloc.h" |
| #include "tests/Test.h" |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <limits> |
| #include <memory> |
| #include <new> |
| |
| DEF_TEST(ArenaAlloc, r) { |
| static int created = 0, |
| destroyed = 0; |
| |
| struct Foo { |
| Foo() : x(-2), y(-3.0f) { created++; } |
| Foo(int X, float Y) : x(X), y(Y) { created++; } |
| ~Foo() { destroyed++; } |
| int x; |
| float y; |
| }; |
| |
| struct alignas(8) OddAlignment { |
| char buf[10]; |
| }; |
| |
| // Check construction/destruction counts from SkArenaAlloc. |
| created = 0; |
| destroyed = 0; |
| { |
| SkArenaAlloc arena{0}; |
| REPORTER_ASSERT(r, *arena.make<int>(3) == 3); |
| Foo* foo = arena.make<Foo>(3, 4.0f); |
| REPORTER_ASSERT(r, foo->x == 3); |
| REPORTER_ASSERT(r, foo->y == 4.0f); |
| REPORTER_ASSERT(r, created == 1); |
| REPORTER_ASSERT(r, destroyed == 0); |
| arena.makeArrayDefault<int>(10); |
| int* zeroed = arena.makeArray<int>(10); |
| for (int i = 0; i < 10; i++) { |
| REPORTER_ASSERT(r, zeroed[i] == 0); |
| } |
| Foo* fooArray = arena.makeArrayDefault<Foo>(10); |
| REPORTER_ASSERT(r, fooArray[3].x == -2); |
| REPORTER_ASSERT(r, fooArray[4].y == -3.0f); |
| REPORTER_ASSERT(r, created == 11); |
| REPORTER_ASSERT(r, destroyed == 0); |
| arena.make<OddAlignment>(); |
| } |
| REPORTER_ASSERT(r, created == 11); |
| REPORTER_ASSERT(r, destroyed == 11); |
| |
| // Check construction/destruction counts from SkSTArenaAlloc. |
| created = 0; |
| destroyed = 0; |
| { |
| SkSTArenaAlloc<64> arena; |
| REPORTER_ASSERT(r, *arena.make<int>(3) == 3); |
| Foo* foo = arena.make<Foo>(3, 4.0f); |
| REPORTER_ASSERT(r, foo->x == 3); |
| REPORTER_ASSERT(r, foo->y == 4.0f); |
| REPORTER_ASSERT(r, created == 1); |
| REPORTER_ASSERT(r, destroyed == 0); |
| arena.makeArrayDefault<int>(10); |
| int* zeroed = arena.makeArray<int>(10); |
| for (int i = 0; i < 10; i++) { |
| REPORTER_ASSERT(r, zeroed[i] == 0); |
| } |
| Foo* fooArray = arena.makeArrayDefault<Foo>(10); |
| REPORTER_ASSERT(r, fooArray[3].x == -2); |
| REPORTER_ASSERT(r, fooArray[4].y == -3.0f); |
| REPORTER_ASSERT(r, created == 11); |
| REPORTER_ASSERT(r, destroyed == 0); |
| arena.make<OddAlignment>(); |
| } |
| REPORTER_ASSERT(r, created == 11); |
| REPORTER_ASSERT(r, destroyed == 11); |
| |
| // Check construction/destruction counts from SkArenaAlloc when passed an initial block. |
| created = 0; |
| destroyed = 0; |
| { |
| std::unique_ptr<char[]> block{new char[1024]}; |
| SkArenaAlloc arena{block.get(), 1024, 0}; |
| REPORTER_ASSERT(r, *arena.make<int>(3) == 3); |
| Foo* foo = arena.make<Foo>(3, 4.0f); |
| REPORTER_ASSERT(r, foo->x == 3); |
| REPORTER_ASSERT(r, foo->y == 4.0f); |
| REPORTER_ASSERT(r, created == 1); |
| REPORTER_ASSERT(r, destroyed == 0); |
| arena.makeArrayDefault<int>(10); |
| int* zeroed = arena.makeArray<int>(10); |
| for (int i = 0; i < 10; i++) { |
| REPORTER_ASSERT(r, zeroed[i] == 0); |
| } |
| Foo* fooArray = arena.makeArrayDefault<Foo>(10); |
| REPORTER_ASSERT(r, fooArray[3].x == -2); |
| REPORTER_ASSERT(r, fooArray[4].y == -3.0f); |
| REPORTER_ASSERT(r, created == 11); |
| REPORTER_ASSERT(r, destroyed == 0); |
| arena.make<OddAlignment>(); |
| } |
| REPORTER_ASSERT(r, created == 11); |
| REPORTER_ASSERT(r, destroyed == 11); |
| } |
| |
| DEF_TEST(ArenaAllocReset, r) { |
| SkSTArenaAllocWithReset<64> arena; |
| arena.makeArrayDefault<char>(256); |
| arena.reset(); |
| arena.reset(); |
| } |
| |
| DEF_TEST(ArenaAllocWithMultipleBlocks, r) { |
| // Make sure that multiple blocks are handled correctly. |
| static int created = 0, |
| destroyed = 0; |
| { |
| struct Node { |
| Node(Node* n) : next(n) { created++; } |
| ~Node() { destroyed++; } |
| Node *next; |
| char filler[64]; |
| }; |
| |
| SkSTArenaAlloc<64> arena; |
| Node* current = nullptr; |
| for (int i = 0; i < 128; i++) { |
| current = arena.make<Node>(current); |
| } |
| } |
| REPORTER_ASSERT(r, created == 128); |
| REPORTER_ASSERT(r, destroyed == 128); |
| } |
| |
| DEF_TEST(ArenaAllocDestructionOrder, r) { |
| // Make sure that objects and blocks are destroyed in the correct order. If they are not, |
| // then there will be a use after free error in asan. |
| static int created = 0, |
| destroyed = 0; |
| { |
| struct Node { |
| Node(Node* n) : next(n) { created++; } |
| ~Node() { |
| destroyed++; |
| if (next) { |
| next->~Node(); |
| } |
| } |
| Node *next; |
| }; |
| |
| SkSTArenaAlloc<64> arena; |
| Node* current = nullptr; |
| for (int i = 0; i < 128; i++) { |
| uint64_t* temp = arena.makeArrayDefault<uint64_t>(sizeof(Node) / sizeof(Node*)); |
| current = new (temp)Node(current); |
| } |
| current->~Node(); |
| } |
| REPORTER_ASSERT(r, created == 128); |
| REPORTER_ASSERT(r, destroyed == 128); |
| |
| { |
| SkSTArenaAlloc<64> arena; |
| auto a = arena.makeInitializedArray<int>(8, [](size_t i ) { return i; }); |
| for (size_t i = 0; i < 8; i++) { |
| REPORTER_ASSERT(r, a[i] == (int)i); |
| } |
| } |
| } |
| |
| DEF_TEST(ArenaAllocUnusualAlignment, r) { |
| SkArenaAlloc arena(4096); |
| // Move to a 1 character boundary. |
| arena.make<char>(); |
| // Allocate something with interesting alignment. |
| void* ptr = arena.makeBytesAlignedTo(4081, 8); |
| REPORTER_ASSERT(r, ((intptr_t)ptr & 7) == 0); |
| } |
| |
| DEF_TEST(SkFibBlockSizes, r) { |
| { |
| SkFibBlockSizes<std::numeric_limits<uint32_t>::max()> fibs{1, 1}; |
| uint32_t lastSize = 1; |
| for (int i = 0; i < 64; i++) { |
| uint32_t size = fibs.nextBlockSize(); |
| REPORTER_ASSERT(r, lastSize <= size); |
| lastSize = size; |
| } |
| REPORTER_ASSERT(r, lastSize == 2971215073u); |
| } |
| { |
| SkFibBlockSizes<std::numeric_limits<uint32_t>::max()> fibs{0, 1024}; |
| uint32_t lastSize = 1; |
| for (int i = 0; i < 64; i++) { |
| uint32_t size = fibs.nextBlockSize(); |
| REPORTER_ASSERT(r, lastSize <= size); |
| lastSize = size; |
| REPORTER_ASSERT(r, lastSize <= std::numeric_limits<uint32_t>::max()); |
| } |
| REPORTER_ASSERT(r, lastSize == 3524578u * 1024); |
| } |
| |
| { |
| SkFibBlockSizes<std::numeric_limits<uint32_t>::max() / 2> fibs{1024, 0}; |
| uint32_t lastSize = 1; |
| for (int i = 0; i < 64; i++) { |
| uint32_t size = fibs.nextBlockSize(); |
| REPORTER_ASSERT(r, lastSize <= size); |
| lastSize = size; |
| REPORTER_ASSERT(r, lastSize <= std::numeric_limits<uint32_t>::max() / 2); |
| } |
| REPORTER_ASSERT(r, lastSize == 1346269u * 1024); |
| } |
| } |