summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/base/SkArenaAlloc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/base/SkArenaAlloc.cpp')
-rw-r--r--gfx/skia/skia/src/base/SkArenaAlloc.cpp173
1 files changed, 173 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/base/SkArenaAlloc.cpp b/gfx/skia/skia/src/base/SkArenaAlloc.cpp
new file mode 100644
index 0000000000..2dc1c00226
--- /dev/null
+++ b/gfx/skia/skia/src/base/SkArenaAlloc.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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 "src/base/SkArenaAlloc.h"
+
+#include "include/private/base/SkMalloc.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+
+static char* end_chain(char*) { return nullptr; }
+
+SkArenaAlloc::SkArenaAlloc(char* block, size_t size, size_t firstHeapAllocation)
+ : fDtorCursor {block}
+ , fCursor {block}
+ , fEnd {block + SkToU32(size)}
+ , fFibonacciProgression{SkToU32(size), SkToU32(firstHeapAllocation)}
+{
+ if (size < sizeof(Footer)) {
+ fEnd = fCursor = fDtorCursor = nullptr;
+ }
+
+ if (fCursor != nullptr) {
+ this->installFooter(end_chain, 0);
+ sk_asan_poison_memory_region(fCursor, fEnd - fCursor);
+ }
+}
+
+SkArenaAlloc::~SkArenaAlloc() {
+ RunDtorsOnBlock(fDtorCursor);
+}
+
+void SkArenaAlloc::installFooter(FooterAction* action, uint32_t padding) {
+ assert(SkTFitsIn<uint8_t>(padding));
+ this->installRaw(action);
+ this->installRaw((uint8_t)padding);
+ fDtorCursor = fCursor;
+}
+
+char* SkArenaAlloc::SkipPod(char* footerEnd) {
+ char* objEnd = footerEnd - (sizeof(Footer) + sizeof(uint32_t));
+ uint32_t skip;
+ memmove(&skip, objEnd, sizeof(uint32_t));
+ return objEnd - (ptrdiff_t) skip;
+}
+
+void SkArenaAlloc::RunDtorsOnBlock(char* footerEnd) {
+ while (footerEnd != nullptr) {
+ FooterAction* action;
+ uint8_t padding;
+
+ memcpy(&action, footerEnd - sizeof( Footer), sizeof( action));
+ memcpy(&padding, footerEnd - sizeof(padding), sizeof(padding));
+
+ footerEnd = action(footerEnd) - (ptrdiff_t)padding;
+ }
+}
+
+char* SkArenaAlloc::NextBlock(char* footerEnd) {
+ char* objEnd = footerEnd - (sizeof(char*) + sizeof(Footer));
+ char* next;
+ memmove(&next, objEnd, sizeof(char*));
+ RunDtorsOnBlock(next);
+ sk_free(objEnd);
+ return nullptr;
+}
+
+void SkArenaAlloc::ensureSpace(uint32_t size, uint32_t alignment) {
+ constexpr uint32_t headerSize = sizeof(Footer) + sizeof(ptrdiff_t);
+ constexpr uint32_t maxSize = std::numeric_limits<uint32_t>::max();
+ constexpr uint32_t overhead = headerSize + sizeof(Footer);
+ AssertRelease(size <= maxSize - overhead);
+ uint32_t objSizeAndOverhead = size + overhead;
+
+ const uint32_t alignmentOverhead = alignment - 1;
+ AssertRelease(objSizeAndOverhead <= maxSize - alignmentOverhead);
+ objSizeAndOverhead += alignmentOverhead;
+
+ uint32_t minAllocationSize = fFibonacciProgression.nextBlockSize();
+ uint32_t allocationSize = std::max(objSizeAndOverhead, minAllocationSize);
+
+ // Round up to a nice size. If > 32K align to 4K boundary else up to max_align_t. The > 32K
+ // heuristic is from the JEMalloc behavior.
+ {
+ uint32_t mask = allocationSize > (1 << 15) ? (1 << 12) - 1 : 16 - 1;
+ AssertRelease(allocationSize <= maxSize - mask);
+ allocationSize = (allocationSize + mask) & ~mask;
+ }
+
+ char* newBlock = static_cast<char*>(sk_malloc_throw(allocationSize));
+
+ auto previousDtor = fDtorCursor;
+ fCursor = newBlock;
+ fDtorCursor = newBlock;
+ fEnd = fCursor + allocationSize;
+
+ // poison the unused bytes in the block.
+ sk_asan_poison_memory_region(fCursor, fEnd - fCursor);
+
+ this->installRaw(previousDtor);
+ this->installFooter(NextBlock, 0);
+}
+
+char* SkArenaAlloc::allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment) {
+ uintptr_t mask = alignment - 1;
+
+restart:
+ uint32_t skipOverhead = 0;
+ const bool needsSkipFooter = fCursor != fDtorCursor;
+ if (needsSkipFooter) {
+ skipOverhead = sizeof(Footer) + sizeof(uint32_t);
+ }
+ const uint32_t totalSize = sizeIncludingFooter + skipOverhead;
+
+ // Math on null fCursor/fEnd is undefined behavior, so explicitly check for first alloc.
+ if (!fCursor) {
+ this->ensureSpace(totalSize, alignment);
+ goto restart;
+ }
+
+ assert(fEnd);
+ // This test alone would be enough nullptr were defined to be 0, but it's not.
+ char* objStart = (char*)((uintptr_t)(fCursor + skipOverhead + mask) & ~mask);
+ if ((ptrdiff_t)totalSize > fEnd - objStart) {
+ this->ensureSpace(totalSize, alignment);
+ goto restart;
+ }
+
+ AssertRelease((ptrdiff_t)totalSize <= fEnd - objStart);
+
+ // Install a skip footer if needed, thus terminating a run of POD data. The calling code is
+ // responsible for installing the footer after the object.
+ if (needsSkipFooter) {
+ this->installRaw(SkToU32(fCursor - fDtorCursor));
+ this->installFooter(SkipPod, 0);
+ }
+
+ return objStart;
+}
+
+SkArenaAllocWithReset::SkArenaAllocWithReset(char* block,
+ size_t size,
+ size_t firstHeapAllocation)
+ : SkArenaAlloc(block, size, firstHeapAllocation)
+ , fFirstBlock{block}
+ , fFirstSize{SkToU32(size)}
+ , fFirstHeapAllocationSize{SkToU32(firstHeapAllocation)} {}
+
+void SkArenaAllocWithReset::reset() {
+ char* const firstBlock = fFirstBlock;
+ const uint32_t firstSize = fFirstSize;
+ const uint32_t firstHeapAllocationSize = fFirstHeapAllocationSize;
+ this->~SkArenaAllocWithReset();
+ new (this) SkArenaAllocWithReset{firstBlock, firstSize, firstHeapAllocationSize};
+}
+
+// SkFibonacci47 is the first 47 Fibonacci numbers. Fib(47) is the largest value less than 2 ^ 32.
+// Used by SkFibBlockSizes.
+std::array<const uint32_t, 47> SkFibonacci47 {
+ 1, 1, 2, 3, 5, 8,
+ 13, 21, 34, 55, 89, 144,
+ 233, 377, 610, 987, 1597, 2584,
+ 4181, 6765, 10946, 17711, 28657, 46368,
+ 75025, 121393, 196418, 317811, 514229, 832040,
+ 1346269, 2178309, 3524578, 5702887, 9227465, 14930352,
+ 24157817, 39088169, 63245986, 102334155, 165580141, 267914296,
+ 433494437, 701408733, 1134903170, 1836311903, 2971215073,
+};