Mike Klein | 58b1306 | 2016-11-11 10:38:49 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2016 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
Herb Derby | 0497f08 | 2017-01-13 11:30:44 -0500 | [diff] [blame] | 8 | #include <algorithm> |
Herb Derby | ac04fef | 2017-01-13 17:34:33 -0500 | [diff] [blame] | 9 | #include "SkArenaAlloc.h" |
Herb Derby | 0497f08 | 2017-01-13 11:30:44 -0500 | [diff] [blame] | 10 | |
| 11 | struct Skipper { |
| 12 | char* operator()(char* objEnd, ptrdiff_t size) { return objEnd + size; } |
| 13 | }; |
| 14 | |
Herb Derby | 1517224 | 2017-01-19 03:32:23 +0000 | [diff] [blame^] | 15 | struct NextBlock { |
| 16 | char* operator()(char* objEnd, ptrdiff_t size) { delete [] objEnd; return objEnd + size; } |
Herb Derby | 0497f08 | 2017-01-13 11:30:44 -0500 | [diff] [blame] | 17 | }; |
| 18 | |
| 19 | SkArenaAlloc::SkArenaAlloc(char* block, size_t size, size_t extraSize) |
Herb Derby | 1517224 | 2017-01-19 03:32:23 +0000 | [diff] [blame^] | 20 | : fDtorCursor{block} |
| 21 | , fCursor {block} |
| 22 | , fEnd {block + size} |
| 23 | , fExtraSize {extraSize} |
Herb Derby | 0497f08 | 2017-01-13 11:30:44 -0500 | [diff] [blame] | 24 | { |
| 25 | if (size < sizeof(Footer)) { |
| 26 | fEnd = fCursor = fDtorCursor = nullptr; |
| 27 | } |
| 28 | |
| 29 | if (fCursor != nullptr) { |
| 30 | this->installFooter(EndChain, 0); |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | SkArenaAlloc::~SkArenaAlloc() { |
Herb Derby | 1517224 | 2017-01-19 03:32:23 +0000 | [diff] [blame^] | 35 | this->reset(); |
Herb Derby | 0497f08 | 2017-01-13 11:30:44 -0500 | [diff] [blame] | 36 | } |
| 37 | |
| 38 | void SkArenaAlloc::reset() { |
Herb Derby | 1517224 | 2017-01-19 03:32:23 +0000 | [diff] [blame^] | 39 | Footer f; |
| 40 | memmove(&f, fDtorCursor - sizeof(Footer), sizeof(Footer)); |
| 41 | char* releaser = fDtorCursor; |
| 42 | while (releaser != nullptr) { |
| 43 | releaser = this->callFooterAction(releaser); |
| 44 | } |
Herb Derby | 0497f08 | 2017-01-13 11:30:44 -0500 | [diff] [blame] | 45 | } |
| 46 | |
| 47 | void SkArenaAlloc::installFooter(FooterAction* releaser, ptrdiff_t padding) { |
| 48 | ptrdiff_t releaserDiff = (char *)releaser - (char *)EndChain; |
| 49 | ptrdiff_t footerData = SkLeftShift((int64_t)releaserDiff, 5) | padding; |
| 50 | if (padding >= 32 || !SkTFitsIn<int32_t>(footerData)) { |
| 51 | // Footer data will not fit. |
| 52 | SkFAIL("Constraints are busted."); |
| 53 | } |
| 54 | |
| 55 | Footer footer = (Footer)(footerData); |
| 56 | memmove(fCursor, &footer, sizeof(Footer)); |
Herb Derby | 1517224 | 2017-01-19 03:32:23 +0000 | [diff] [blame^] | 57 | Footer check; |
| 58 | memmove(&check, fCursor, sizeof(Footer)); |
Herb Derby | 0497f08 | 2017-01-13 11:30:44 -0500 | [diff] [blame] | 59 | fCursor += sizeof(Footer); |
| 60 | fDtorCursor = fCursor; |
| 61 | } |
| 62 | |
| 63 | void SkArenaAlloc::ensureSpace(size_t size, size_t alignment) { |
| 64 | constexpr size_t headerSize = sizeof(Footer) + sizeof(ptrdiff_t); |
| 65 | // The chrome c++ library we use does not define std::max_align_t. |
| 66 | // This must be conservative to add the right amount of extra memory to handle the alignment |
| 67 | // padding. |
| 68 | constexpr size_t alignof_max_align_t = 8; |
| 69 | auto objSizeAndOverhead = size + headerSize + sizeof(Footer); |
| 70 | if (alignment > alignof_max_align_t) { |
| 71 | objSizeAndOverhead += alignment - 1; |
| 72 | } |
| 73 | |
| 74 | auto allocationSize = std::max(objSizeAndOverhead, fExtraSize); |
| 75 | |
| 76 | // Round up to a nice size. If > 32K align to 4K boundary else up to max_align_t. The > 32K |
| 77 | // heuristic is from the JEMalloc behavior. |
| 78 | { |
| 79 | size_t mask = allocationSize > (1 << 15) ? (1 << 12) - 1 : 32 - 1; |
| 80 | allocationSize = (allocationSize + mask) & ~mask; |
| 81 | } |
| 82 | |
| 83 | char* newBlock = new char[allocationSize]; |
| 84 | |
| 85 | auto previousDtor = fDtorCursor; |
| 86 | fCursor = newBlock; |
| 87 | fDtorCursor = newBlock; |
| 88 | fEnd = fCursor + allocationSize; |
| 89 | this->installIntFooter<NextBlock>(previousDtor - fCursor, 0); |
| 90 | } |
| 91 | |
| 92 | char* SkArenaAlloc::allocObject(size_t size, size_t alignment) { |
| 93 | size_t mask = alignment - 1; |
| 94 | char* objStart = (char*)((uintptr_t)(fCursor + mask) & ~mask); |
| 95 | if (objStart + size > fEnd) { |
| 96 | this->ensureSpace(size, alignment); |
| 97 | objStart = (char*)((uintptr_t)(fCursor + mask) & ~mask); |
| 98 | } |
| 99 | return objStart; |
| 100 | } |
| 101 | |
| 102 | // * sizeAndFooter - the memory for the footer in addition to the size for the object. |
| 103 | // * alignment - alignment needed by the object. |
| 104 | char* SkArenaAlloc::allocObjectWithFooter(size_t sizeIncludingFooter, size_t alignment) { |
| 105 | size_t mask = alignment - 1; |
| 106 | |
Herb Derby | 1517224 | 2017-01-19 03:32:23 +0000 | [diff] [blame^] | 107 | restart: |
Herb Derby | 0497f08 | 2017-01-13 11:30:44 -0500 | [diff] [blame] | 108 | size_t skipOverhead = 0; |
| 109 | bool needsSkipFooter = fCursor != fDtorCursor; |
| 110 | if (needsSkipFooter) { |
| 111 | size_t skipSize = SkTFitsIn<int32_t>(fDtorCursor - fCursor) |
| 112 | ? sizeof(int32_t) |
| 113 | : sizeof(ptrdiff_t); |
| 114 | skipOverhead = sizeof(Footer) + skipSize; |
| 115 | } |
| 116 | char* objStart = (char*)((uintptr_t)(fCursor + skipOverhead + mask) & ~mask); |
| 117 | size_t totalSize = sizeIncludingFooter + skipOverhead; |
| 118 | |
| 119 | if (objStart + totalSize > fEnd) { |
| 120 | this->ensureSpace(totalSize, alignment); |
| 121 | goto restart; |
| 122 | } |
| 123 | |
| 124 | SkASSERT(objStart + totalSize <= fEnd); |
| 125 | |
| 126 | // Install a skip footer if needed, thus terminating a run of POD data. The calling code is |
| 127 | // responsible for installing the footer after the object. |
| 128 | if (needsSkipFooter) { |
| 129 | this->installIntFooter<Skipper>(fDtorCursor - fCursor, 0); |
| 130 | } |
| 131 | |
| 132 | return objStart; |
| 133 | } |
| 134 | |
Herb Derby | 1517224 | 2017-01-19 03:32:23 +0000 | [diff] [blame^] | 135 | char* SkArenaAlloc::callFooterAction(char* end) { |
Herb Derby | 412a86d | 2017-01-18 17:07:48 -0500 | [diff] [blame] | 136 | Footer footer; |
Herb Derby | 1517224 | 2017-01-19 03:32:23 +0000 | [diff] [blame^] | 137 | memcpy(&footer, end - sizeof(Footer), sizeof(Footer)); |
Herb Derby | 412a86d | 2017-01-18 17:07:48 -0500 | [diff] [blame] | 138 | |
Herb Derby | 1517224 | 2017-01-19 03:32:23 +0000 | [diff] [blame^] | 139 | FooterAction* releaser = (FooterAction*)((char*)EndChain + (footer >> 5)); |
Herb Derby | 0497f08 | 2017-01-13 11:30:44 -0500 | [diff] [blame] | 140 | ptrdiff_t padding = footer & 31; |
| 141 | |
Herb Derby | 1517224 | 2017-01-19 03:32:23 +0000 | [diff] [blame^] | 142 | char* r = releaser(end) - padding; |
Herb Derby | 0497f08 | 2017-01-13 11:30:44 -0500 | [diff] [blame] | 143 | |
| 144 | return r; |
| 145 | } |
| 146 | |
| 147 | char* SkArenaAlloc::EndChain(char*) { return nullptr; } |
| 148 | |