/* * 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/SkRefCnt.h" #include "include/core/SkTypes.h" #include "src/core/SkArenaAlloc.h" #include "tests/Test.h" #include #include #include 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(3) == 3); Foo* foo = arena.make(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(10); int* zeroed = arena.makeArray(10); for (int i = 0; i < 10; i++) { REPORTER_ASSERT(r, zeroed[i] == 0); } Foo* fooArray = arena.makeArrayDefault(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(); } 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(3) == 3); Foo* foo = arena.make(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(10); int* zeroed = arena.makeArray(10); for (int i = 0; i < 10; i++) { REPORTER_ASSERT(r, zeroed[i] == 0); } Foo* fooArray = arena.makeArrayDefault(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(); } 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 block{new char[1024]}; SkArenaAlloc arena{block.get(), 1024, 0}; REPORTER_ASSERT(r, *arena.make(3) == 3); Foo* foo = arena.make(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(10); int* zeroed = arena.makeArray(10); for (int i = 0; i < 10; i++) { REPORTER_ASSERT(r, zeroed[i] == 0); } Foo* fooArray = arena.makeArrayDefault(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(); } REPORTER_ASSERT(r, created == 11); REPORTER_ASSERT(r, destroyed == 11); } DEF_TEST(ArenaAllocReset, r) { SkSTArenaAllocWithReset<64> arena; arena.makeArrayDefault(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(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(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(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(); // Allocate something with interesting alignment. void* ptr = arena.makeBytesAlignedTo(4081, 8); REPORTER_ASSERT(r, ((intptr_t)ptr & 7) == 0); } DEF_TEST(SkFibBlockSizes, r) { { SkFibBlockSizes::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::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::max()); } REPORTER_ASSERT(r, lastSize == 3524578u * 1024); } { SkFibBlockSizes::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::max() / 2); } REPORTER_ASSERT(r, lastSize == 1346269u * 1024); } }