SkArenaAlloc.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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. #include "src/core/SkArenaAlloc.h"
  8. #include <algorithm>
  9. #include <new>
  10. static char* end_chain(char*) { return nullptr; }
  11. static uint32_t first_allocated_block(uint32_t blockSize, uint32_t firstHeapAllocation) {
  12. return firstHeapAllocation > 0 ? firstHeapAllocation :
  13. blockSize > 0 ? blockSize : 1024;
  14. }
  15. SkArenaAlloc::SkArenaAlloc(char* block, size_t size, size_t firstHeapAllocation)
  16. : fDtorCursor {block}
  17. , fCursor {block}
  18. , fEnd {block + ToU32(size)}
  19. , fFirstBlock {block}
  20. , fFirstSize {ToU32(size)}
  21. , fFirstHeapAllocationSize {first_allocated_block(ToU32(size), ToU32(firstHeapAllocation))}
  22. {
  23. if (size < sizeof(Footer)) {
  24. fEnd = fCursor = fDtorCursor = nullptr;
  25. }
  26. if (fCursor != nullptr) {
  27. this->installFooter(end_chain, 0);
  28. }
  29. }
  30. SkArenaAlloc::~SkArenaAlloc() {
  31. RunDtorsOnBlock(fDtorCursor);
  32. }
  33. void SkArenaAlloc::reset() {
  34. this->~SkArenaAlloc();
  35. new (this) SkArenaAlloc{fFirstBlock, fFirstSize, fFirstHeapAllocationSize};
  36. }
  37. void SkArenaAlloc::installFooter(FooterAction* action, uint32_t padding) {
  38. assert(padding < 64);
  39. int64_t actionInt = (int64_t)(intptr_t)action;
  40. // The top 14 bits should be either all 0s or all 1s. Check this.
  41. assert((actionInt << 6) >> 6 == actionInt);
  42. Footer encodedFooter = (actionInt << 6) | padding;
  43. memmove(fCursor, &encodedFooter, sizeof(Footer));
  44. fCursor += sizeof(Footer);
  45. fDtorCursor = fCursor;
  46. }
  47. void SkArenaAlloc::installPtrFooter(FooterAction* action, char* ptr, uint32_t padding) {
  48. memmove(fCursor, &ptr, sizeof(char*));
  49. fCursor += sizeof(char*);
  50. this->installFooter(action, padding);
  51. }
  52. char* SkArenaAlloc::SkipPod(char* footerEnd) {
  53. char* objEnd = footerEnd - (sizeof(Footer) + sizeof(int32_t));
  54. int32_t skip;
  55. memmove(&skip, objEnd, sizeof(int32_t));
  56. return objEnd - skip;
  57. }
  58. void SkArenaAlloc::RunDtorsOnBlock(char* footerEnd) {
  59. while (footerEnd != nullptr) {
  60. Footer footer;
  61. memcpy(&footer, footerEnd - sizeof(Footer), sizeof(Footer));
  62. FooterAction* action = (FooterAction*)(footer >> 6);
  63. ptrdiff_t padding = footer & 63;
  64. footerEnd = action(footerEnd) - padding;
  65. }
  66. }
  67. char* SkArenaAlloc::NextBlock(char* footerEnd) {
  68. char* objEnd = footerEnd - (sizeof(Footer) + sizeof(char*));
  69. char* next;
  70. memmove(&next, objEnd, sizeof(char*));
  71. RunDtorsOnBlock(next);
  72. delete [] objEnd;
  73. return nullptr;
  74. }
  75. void SkArenaAlloc::installUint32Footer(FooterAction* action, uint32_t value, uint32_t padding) {
  76. memmove(fCursor, &value, sizeof(uint32_t));
  77. fCursor += sizeof(uint32_t);
  78. this->installFooter(action, padding);
  79. }
  80. void SkArenaAlloc::ensureSpace(uint32_t size, uint32_t alignment) {
  81. constexpr uint32_t headerSize = sizeof(Footer) + sizeof(ptrdiff_t);
  82. // The chrome c++ library we use does not define std::max_align_t.
  83. // This must be conservative to add the right amount of extra memory to handle the alignment
  84. // padding.
  85. constexpr uint32_t alignof_max_align_t = 8;
  86. constexpr uint32_t maxSize = std::numeric_limits<uint32_t>::max();
  87. constexpr uint32_t overhead = headerSize + sizeof(Footer);
  88. AssertRelease(size <= maxSize - overhead);
  89. uint32_t objSizeAndOverhead = size + overhead;
  90. if (alignment > alignof_max_align_t) {
  91. uint32_t alignmentOverhead = alignment - 1;
  92. AssertRelease(objSizeAndOverhead <= maxSize - alignmentOverhead);
  93. objSizeAndOverhead += alignmentOverhead;
  94. }
  95. uint32_t minAllocationSize;
  96. if (fFirstHeapAllocationSize <= maxSize / fFib0) {
  97. minAllocationSize = fFirstHeapAllocationSize * fFib0;
  98. fFib0 += fFib1;
  99. std::swap(fFib0, fFib1);
  100. } else {
  101. minAllocationSize = maxSize;
  102. }
  103. uint32_t allocationSize = std::max(objSizeAndOverhead, minAllocationSize);
  104. // Round up to a nice size. If > 32K align to 4K boundary else up to max_align_t. The > 32K
  105. // heuristic is from the JEMalloc behavior.
  106. {
  107. uint32_t mask = allocationSize > (1 << 15) ? (1 << 12) - 1 : 16 - 1;
  108. AssertRelease(allocationSize <= maxSize - mask);
  109. allocationSize = (allocationSize + mask) & ~mask;
  110. }
  111. char* newBlock = new char[allocationSize];
  112. auto previousDtor = fDtorCursor;
  113. fCursor = newBlock;
  114. fDtorCursor = newBlock;
  115. fEnd = fCursor + allocationSize;
  116. this->installPtrFooter(NextBlock, previousDtor, 0);
  117. }
  118. char* SkArenaAlloc::allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment) {
  119. uintptr_t mask = alignment - 1;
  120. restart:
  121. uint32_t skipOverhead = 0;
  122. bool needsSkipFooter = fCursor != fDtorCursor;
  123. if (needsSkipFooter) {
  124. skipOverhead = sizeof(Footer) + sizeof(uint32_t);
  125. }
  126. char* objStart = (char*)((uintptr_t)(fCursor + skipOverhead + mask) & ~mask);
  127. uint32_t totalSize = sizeIncludingFooter + skipOverhead;
  128. if ((ptrdiff_t)totalSize > fEnd - objStart) {
  129. this->ensureSpace(totalSize, alignment);
  130. goto restart;
  131. }
  132. AssertRelease((ptrdiff_t)totalSize <= fEnd - objStart);
  133. // Install a skip footer if needed, thus terminating a run of POD data. The calling code is
  134. // responsible for installing the footer after the object.
  135. if (needsSkipFooter) {
  136. this->installUint32Footer(SkipPod, ToU32(fCursor - fDtorCursor), 0);
  137. }
  138. return objStart;
  139. }