|  | /* | 
|  | * 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); | 
|  | } | 
|  | } |