1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h" 9cb93a386Sopenharmony_ci#include <algorithm> 10cb93a386Sopenharmony_ci#include <new> 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_cistatic char* end_chain(char*) { return nullptr; } 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ciSkArenaAlloc::SkArenaAlloc(char* block, size_t size, size_t firstHeapAllocation) 15cb93a386Sopenharmony_ci : fDtorCursor {block} 16cb93a386Sopenharmony_ci , fCursor {block} 17cb93a386Sopenharmony_ci , fEnd {block + SkToU32(size)} 18cb93a386Sopenharmony_ci , fFibonacciProgression{SkToU32(size), SkToU32(firstHeapAllocation)} 19cb93a386Sopenharmony_ci{ 20cb93a386Sopenharmony_ci if (size < sizeof(Footer)) { 21cb93a386Sopenharmony_ci fEnd = fCursor = fDtorCursor = nullptr; 22cb93a386Sopenharmony_ci } 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci if (fCursor != nullptr) { 25cb93a386Sopenharmony_ci this->installFooter(end_chain, 0); 26cb93a386Sopenharmony_ci } 27cb93a386Sopenharmony_ci} 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ciSkArenaAlloc::~SkArenaAlloc() { 30cb93a386Sopenharmony_ci RunDtorsOnBlock(fDtorCursor); 31cb93a386Sopenharmony_ci} 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_civoid SkArenaAlloc::installFooter(FooterAction* action, uint32_t padding) { 34cb93a386Sopenharmony_ci assert(SkTFitsIn<uint8_t>(padding)); 35cb93a386Sopenharmony_ci this->installRaw(action); 36cb93a386Sopenharmony_ci this->installRaw((uint8_t)padding); 37cb93a386Sopenharmony_ci fDtorCursor = fCursor; 38cb93a386Sopenharmony_ci} 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_cichar* SkArenaAlloc::SkipPod(char* footerEnd) { 41cb93a386Sopenharmony_ci char* objEnd = footerEnd - (sizeof(Footer) + sizeof(int32_t)); 42cb93a386Sopenharmony_ci int32_t skip; 43cb93a386Sopenharmony_ci memmove(&skip, objEnd, sizeof(int32_t)); 44cb93a386Sopenharmony_ci return objEnd - skip; 45cb93a386Sopenharmony_ci} 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_civoid SkArenaAlloc::RunDtorsOnBlock(char* footerEnd) { 48cb93a386Sopenharmony_ci while (footerEnd != nullptr) { 49cb93a386Sopenharmony_ci FooterAction* action; 50cb93a386Sopenharmony_ci uint8_t padding; 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci memcpy(&action, footerEnd - sizeof( Footer), sizeof( action)); 53cb93a386Sopenharmony_ci memcpy(&padding, footerEnd - sizeof(padding), sizeof(padding)); 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci footerEnd = action(footerEnd) - (ptrdiff_t)padding; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci} 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_cichar* SkArenaAlloc::NextBlock(char* footerEnd) { 60cb93a386Sopenharmony_ci char* objEnd = footerEnd - (sizeof(char*) + sizeof(Footer)); 61cb93a386Sopenharmony_ci char* next; 62cb93a386Sopenharmony_ci memmove(&next, objEnd, sizeof(char*)); 63cb93a386Sopenharmony_ci RunDtorsOnBlock(next); 64cb93a386Sopenharmony_ci delete [] objEnd; 65cb93a386Sopenharmony_ci return nullptr; 66cb93a386Sopenharmony_ci} 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_civoid SkArenaAlloc::ensureSpace(uint32_t size, uint32_t alignment) { 70cb93a386Sopenharmony_ci constexpr uint32_t headerSize = sizeof(Footer) + sizeof(ptrdiff_t); 71cb93a386Sopenharmony_ci constexpr uint32_t maxSize = std::numeric_limits<uint32_t>::max(); 72cb93a386Sopenharmony_ci constexpr uint32_t overhead = headerSize + sizeof(Footer); 73cb93a386Sopenharmony_ci AssertRelease(size <= maxSize - overhead); 74cb93a386Sopenharmony_ci uint32_t objSizeAndOverhead = size + overhead; 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci const uint32_t alignmentOverhead = alignment - 1; 77cb93a386Sopenharmony_ci AssertRelease(objSizeAndOverhead <= maxSize - alignmentOverhead); 78cb93a386Sopenharmony_ci objSizeAndOverhead += alignmentOverhead; 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci uint32_t minAllocationSize = fFibonacciProgression.nextBlockSize(); 81cb93a386Sopenharmony_ci uint32_t allocationSize = std::max(objSizeAndOverhead, minAllocationSize); 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci // Round up to a nice size. If > 32K align to 4K boundary else up to max_align_t. The > 32K 84cb93a386Sopenharmony_ci // heuristic is from the JEMalloc behavior. 85cb93a386Sopenharmony_ci { 86cb93a386Sopenharmony_ci uint32_t mask = allocationSize > (1 << 15) ? (1 << 12) - 1 : 16 - 1; 87cb93a386Sopenharmony_ci AssertRelease(allocationSize <= maxSize - mask); 88cb93a386Sopenharmony_ci allocationSize = (allocationSize + mask) & ~mask; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci char* newBlock = new char[allocationSize]; 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci auto previousDtor = fDtorCursor; 94cb93a386Sopenharmony_ci fCursor = newBlock; 95cb93a386Sopenharmony_ci fDtorCursor = newBlock; 96cb93a386Sopenharmony_ci fEnd = fCursor + allocationSize; 97cb93a386Sopenharmony_ci this->installRaw(previousDtor); 98cb93a386Sopenharmony_ci this->installFooter(NextBlock, 0); 99cb93a386Sopenharmony_ci} 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_cichar* SkArenaAlloc::allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment) { 102cb93a386Sopenharmony_ci uintptr_t mask = alignment - 1; 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_cirestart: 105cb93a386Sopenharmony_ci uint32_t skipOverhead = 0; 106cb93a386Sopenharmony_ci const bool needsSkipFooter = fCursor != fDtorCursor; 107cb93a386Sopenharmony_ci if (needsSkipFooter) { 108cb93a386Sopenharmony_ci skipOverhead = sizeof(Footer) + sizeof(uint32_t); 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci const uint32_t totalSize = sizeIncludingFooter + skipOverhead; 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci // Math on null fCursor/fEnd is undefined behavior, so explicitly check for first alloc. 113cb93a386Sopenharmony_ci if (!fCursor) { 114cb93a386Sopenharmony_ci this->ensureSpace(totalSize, alignment); 115cb93a386Sopenharmony_ci goto restart; 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci assert(fEnd); 119cb93a386Sopenharmony_ci // This test alone would be enough nullptr were defined to be 0, but it's not. 120cb93a386Sopenharmony_ci char* objStart = (char*)((uintptr_t)(fCursor + skipOverhead + mask) & ~mask); 121cb93a386Sopenharmony_ci if ((ptrdiff_t)totalSize > fEnd - objStart) { 122cb93a386Sopenharmony_ci this->ensureSpace(totalSize, alignment); 123cb93a386Sopenharmony_ci goto restart; 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci AssertRelease((ptrdiff_t)totalSize <= fEnd - objStart); 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ci // Install a skip footer if needed, thus terminating a run of POD data. The calling code is 129cb93a386Sopenharmony_ci // responsible for installing the footer after the object. 130cb93a386Sopenharmony_ci if (needsSkipFooter) { 131cb93a386Sopenharmony_ci this->installRaw(SkToU32(fCursor - fDtorCursor)); 132cb93a386Sopenharmony_ci this->installFooter(SkipPod, 0); 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci return objStart; 136cb93a386Sopenharmony_ci} 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ciSkArenaAllocWithReset::SkArenaAllocWithReset(char* block, 139cb93a386Sopenharmony_ci size_t size, 140cb93a386Sopenharmony_ci size_t firstHeapAllocation) 141cb93a386Sopenharmony_ci : SkArenaAlloc(block, size, firstHeapAllocation) 142cb93a386Sopenharmony_ci , fFirstBlock{block} 143cb93a386Sopenharmony_ci , fFirstSize{SkToU32(size)} 144cb93a386Sopenharmony_ci , fFirstHeapAllocationSize{SkToU32(firstHeapAllocation)} {} 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_civoid SkArenaAllocWithReset::reset() { 147cb93a386Sopenharmony_ci this->~SkArenaAllocWithReset(); 148cb93a386Sopenharmony_ci new (this) SkArenaAllocWithReset{fFirstBlock, fFirstSize, fFirstHeapAllocationSize}; 149cb93a386Sopenharmony_ci} 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci// SkFibonacci47 is the first 47 Fibonacci numbers. Fib(47) is the largest value less than 2 ^ 32. 152cb93a386Sopenharmony_ci// Used by SkFibBlockSizes. 153cb93a386Sopenharmony_cistd::array<const uint32_t, 47> SkFibonacci47 { 154cb93a386Sopenharmony_ci 1, 1, 2, 3, 5, 8, 155cb93a386Sopenharmony_ci 13, 21, 34, 55, 89, 144, 156cb93a386Sopenharmony_ci 233, 377, 610, 987, 1597, 2584, 157cb93a386Sopenharmony_ci 4181, 6765, 10946, 17711, 28657, 46368, 158cb93a386Sopenharmony_ci 75025, 121393, 196418, 317811, 514229, 832040, 159cb93a386Sopenharmony_ci 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 160cb93a386Sopenharmony_ci 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 161cb93a386Sopenharmony_ci 433494437, 701408733, 1134903170, 1836311903, 2971215073, 162cb93a386Sopenharmony_ci}; 163