123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /*
- * 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/core/SkArenaAlloc.h"
- #include <algorithm>
- #include <new>
- static char* end_chain(char*) { return nullptr; }
- static uint32_t first_allocated_block(uint32_t blockSize, uint32_t firstHeapAllocation) {
- return firstHeapAllocation > 0 ? firstHeapAllocation :
- blockSize > 0 ? blockSize : 1024;
- }
- SkArenaAlloc::SkArenaAlloc(char* block, size_t size, size_t firstHeapAllocation)
- : fDtorCursor {block}
- , fCursor {block}
- , fEnd {block + ToU32(size)}
- , fFirstBlock {block}
- , fFirstSize {ToU32(size)}
- , fFirstHeapAllocationSize {first_allocated_block(ToU32(size), ToU32(firstHeapAllocation))}
- {
- if (size < sizeof(Footer)) {
- fEnd = fCursor = fDtorCursor = nullptr;
- }
- if (fCursor != nullptr) {
- this->installFooter(end_chain, 0);
- }
- }
- SkArenaAlloc::~SkArenaAlloc() {
- RunDtorsOnBlock(fDtorCursor);
- }
- void SkArenaAlloc::reset() {
- this->~SkArenaAlloc();
- new (this) SkArenaAlloc{fFirstBlock, fFirstSize, fFirstHeapAllocationSize};
- }
- void SkArenaAlloc::installFooter(FooterAction* action, uint32_t padding) {
- assert(padding < 64);
- int64_t actionInt = (int64_t)(intptr_t)action;
- // The top 14 bits should be either all 0s or all 1s. Check this.
- assert((actionInt << 6) >> 6 == actionInt);
- Footer encodedFooter = (actionInt << 6) | padding;
- memmove(fCursor, &encodedFooter, sizeof(Footer));
- fCursor += sizeof(Footer);
- fDtorCursor = fCursor;
- }
- void SkArenaAlloc::installPtrFooter(FooterAction* action, char* ptr, uint32_t padding) {
- memmove(fCursor, &ptr, sizeof(char*));
- fCursor += sizeof(char*);
- this->installFooter(action, padding);
- }
- char* SkArenaAlloc::SkipPod(char* footerEnd) {
- char* objEnd = footerEnd - (sizeof(Footer) + sizeof(int32_t));
- int32_t skip;
- memmove(&skip, objEnd, sizeof(int32_t));
- return objEnd - skip;
- }
- void SkArenaAlloc::RunDtorsOnBlock(char* footerEnd) {
- while (footerEnd != nullptr) {
- Footer footer;
- memcpy(&footer, footerEnd - sizeof(Footer), sizeof(Footer));
- FooterAction* action = (FooterAction*)(footer >> 6);
- ptrdiff_t padding = footer & 63;
- footerEnd = action(footerEnd) - padding;
- }
- }
- char* SkArenaAlloc::NextBlock(char* footerEnd) {
- char* objEnd = footerEnd - (sizeof(Footer) + sizeof(char*));
- char* next;
- memmove(&next, objEnd, sizeof(char*));
- RunDtorsOnBlock(next);
- delete [] objEnd;
- return nullptr;
- }
- void SkArenaAlloc::installUint32Footer(FooterAction* action, uint32_t value, uint32_t padding) {
- memmove(fCursor, &value, sizeof(uint32_t));
- fCursor += sizeof(uint32_t);
- this->installFooter(action, padding);
- }
- void SkArenaAlloc::ensureSpace(uint32_t size, uint32_t alignment) {
- constexpr uint32_t headerSize = sizeof(Footer) + sizeof(ptrdiff_t);
- // The chrome c++ library we use does not define std::max_align_t.
- // This must be conservative to add the right amount of extra memory to handle the alignment
- // padding.
- constexpr uint32_t alignof_max_align_t = 8;
- 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;
- if (alignment > alignof_max_align_t) {
- uint32_t alignmentOverhead = alignment - 1;
- AssertRelease(objSizeAndOverhead <= maxSize - alignmentOverhead);
- objSizeAndOverhead += alignmentOverhead;
- }
- uint32_t minAllocationSize;
- if (fFirstHeapAllocationSize <= maxSize / fFib0) {
- minAllocationSize = fFirstHeapAllocationSize * fFib0;
- fFib0 += fFib1;
- std::swap(fFib0, fFib1);
- } else {
- minAllocationSize = maxSize;
- }
- 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 = new char[allocationSize];
- auto previousDtor = fDtorCursor;
- fCursor = newBlock;
- fDtorCursor = newBlock;
- fEnd = fCursor + allocationSize;
- this->installPtrFooter(NextBlock, previousDtor, 0);
- }
- char* SkArenaAlloc::allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment) {
- uintptr_t mask = alignment - 1;
- restart:
- uint32_t skipOverhead = 0;
- bool needsSkipFooter = fCursor != fDtorCursor;
- if (needsSkipFooter) {
- skipOverhead = sizeof(Footer) + sizeof(uint32_t);
- }
- char* objStart = (char*)((uintptr_t)(fCursor + skipOverhead + mask) & ~mask);
- uint32_t totalSize = sizeIncludingFooter + skipOverhead;
- 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->installUint32Footer(SkipPod, ToU32(fCursor - fDtorCursor), 0);
- }
- return objStart;
- }
|