aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/core/SkArenaAlloc.cpp104
-rw-r--r--src/core/SkArenaAlloc.h86
-rw-r--r--tests/ArenaAllocTest.cpp48
3 files changed, 136 insertions, 102 deletions
diff --git a/src/core/SkArenaAlloc.cpp b/src/core/SkArenaAlloc.cpp
index d6c249b573..1d359d182c 100644
--- a/src/core/SkArenaAlloc.cpp
+++ b/src/core/SkArenaAlloc.cpp
@@ -6,46 +6,71 @@
*/
#include <algorithm>
+#include <cstddef>
#include "SkArenaAlloc.h"
-struct Skipper {
- char* operator()(char* objEnd, ptrdiff_t size) { return objEnd + size; }
-};
+static char* end_chain(char*) { return nullptr; }
+
+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*)((char*)end_chain + (footer >> 5));
+ ptrdiff_t padding = footer & 31;
-struct NextBlock {
- char* operator()(char* objEnd, ptrdiff_t size) { delete [] objEnd; return objEnd + size; }
+ 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;
+}
+
+struct Skipper {
+ char* operator()(char* objEnd, uint32_t size) { return objEnd - size; }
};
SkArenaAlloc::SkArenaAlloc(char* block, size_t size, size_t extraSize)
- : fDtorCursor{block}
- , fCursor {block}
- , fEnd {block + size}
- , fExtraSize {extraSize}
+ : fDtorCursor {block}
+ , fCursor {block}
+ , fEnd {block + size}
+ , fFirstBlock {block}
+ , fFirstSize {size}
+ , fExtraSize {extraSize}
{
if (size < sizeof(Footer)) {
fEnd = fCursor = fDtorCursor = nullptr;
}
if (fCursor != nullptr) {
- this->installFooter(EndChain, 0);
+ this->installFooter(end_chain, 0);
}
}
SkArenaAlloc::~SkArenaAlloc() {
- this->reset();
+ RunDtorsOnBlock(fDtorCursor);
}
void SkArenaAlloc::reset() {
- Footer f;
- memmove(&f, fDtorCursor - sizeof(Footer), sizeof(Footer));
- char* releaser = fDtorCursor;
- while (releaser != nullptr) {
- releaser = this->callFooterAction(releaser);
- }
+ this->~SkArenaAlloc();
+ new (this) SkArenaAlloc{fFirstBlock, fFirstSize, fExtraSize};
}
void SkArenaAlloc::installFooter(FooterAction* releaser, ptrdiff_t padding) {
- ptrdiff_t releaserDiff = (char *)releaser - (char *)EndChain;
+ ptrdiff_t releaserDiff = (char *)releaser - (char *)end_chain;
ptrdiff_t footerData = SkLeftShift((int64_t)releaserDiff, 5) | padding;
if (padding >= 32 || !SkTFitsIn<int32_t>(footerData)) {
// Footer data will not fit.
@@ -54,12 +79,22 @@ void SkArenaAlloc::installFooter(FooterAction* releaser, ptrdiff_t padding) {
Footer footer = (Footer)(footerData);
memmove(fCursor, &footer, sizeof(Footer));
- Footer check;
- memmove(&check, fCursor, sizeof(Footer));
fCursor += sizeof(Footer);
fDtorCursor = fCursor;
}
+void SkArenaAlloc::installPtrFooter(FooterAction* action, char* ptr, ptrdiff_t padding) {
+ memmove(fCursor, &ptr, sizeof(char*));
+ fCursor += sizeof(char*);
+ this->installFooter(action, padding);
+}
+
+void SkArenaAlloc::installUint32Footer(FooterAction* action, uint32_t value, ptrdiff_t padding) {
+ memmove(fCursor, &value, sizeof(uint32_t));
+ fCursor += sizeof(uint32_t);
+ this->installFooter(action, padding);
+}
+
void SkArenaAlloc::ensureSpace(size_t size, size_t alignment) {
constexpr size_t headerSize = sizeof(Footer) + sizeof(ptrdiff_t);
// The chrome c++ library we use does not define std::max_align_t.
@@ -76,7 +111,7 @@ void SkArenaAlloc::ensureSpace(size_t size, size_t alignment) {
// 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.
{
- size_t mask = allocationSize > (1 << 15) ? (1 << 12) - 1 : 32 - 1;
+ size_t mask = allocationSize > (1 << 15) ? (1 << 12) - 1 : 16 - 1;
allocationSize = (allocationSize + mask) & ~mask;
}
@@ -86,7 +121,7 @@ void SkArenaAlloc::ensureSpace(size_t size, size_t alignment) {
fCursor = newBlock;
fDtorCursor = newBlock;
fEnd = fCursor + allocationSize;
- this->installIntFooter<NextBlock>(previousDtor - fCursor, 0);
+ this->installPtrFooter(NextBlock, previousDtor, 0);
}
char* SkArenaAlloc::allocObject(size_t size, size_t alignment) {
@@ -99,19 +134,14 @@ char* SkArenaAlloc::allocObject(size_t size, size_t alignment) {
return objStart;
}
-// * sizeAndFooter - the memory for the footer in addition to the size for the object.
-// * alignment - alignment needed by the object.
char* SkArenaAlloc::allocObjectWithFooter(size_t sizeIncludingFooter, size_t alignment) {
size_t mask = alignment - 1;
- restart:
+restart:
size_t skipOverhead = 0;
bool needsSkipFooter = fCursor != fDtorCursor;
if (needsSkipFooter) {
- size_t skipSize = SkTFitsIn<int32_t>(fDtorCursor - fCursor)
- ? sizeof(int32_t)
- : sizeof(ptrdiff_t);
- skipOverhead = sizeof(Footer) + skipSize;
+ skipOverhead = sizeof(Footer) + sizeof(uint32_t);
}
char* objStart = (char*)((uintptr_t)(fCursor + skipOverhead + mask) & ~mask);
size_t totalSize = sizeIncludingFooter + skipOverhead;
@@ -126,23 +156,9 @@ char* SkArenaAlloc::allocObjectWithFooter(size_t sizeIncludingFooter, size_t ali
// 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->installIntFooter<Skipper>(fDtorCursor - fCursor, 0);
+ this->installUint32Footer(SkipPod, SkTo<uint32_t>(fCursor - fDtorCursor), 0);
}
return objStart;
}
-char* SkArenaAlloc::callFooterAction(char* end) {
- Footer footer;
- memcpy(&footer, end - sizeof(Footer), sizeof(Footer));
-
- FooterAction* releaser = (FooterAction*)((char*)EndChain + (footer >> 5));
- ptrdiff_t padding = footer & 31;
-
- char* r = releaser(end) - padding;
-
- return r;
-}
-
-char* SkArenaAlloc::EndChain(char*) { return nullptr; }
-
diff --git a/src/core/SkArenaAlloc.h b/src/core/SkArenaAlloc.h
index 8152c94cbd..7deac72bd8 100644
--- a/src/core/SkArenaAlloc.h
+++ b/src/core/SkArenaAlloc.h
@@ -56,7 +56,7 @@ public:
SkArenaAlloc(char* block, size_t size, size_t extraSize = 0);
template <size_t kSize>
- SkArenaAlloc(char (&block)[kSize], size_t extraSize = 0)
+ SkArenaAlloc(char (&block)[kSize], size_t extraSize = kSize)
: SkArenaAlloc(block, kSize, extraSize)
{}
@@ -116,38 +116,13 @@ private:
using Footer = int32_t;
using FooterAction = char* (char*);
- void installFooter(FooterAction* releaser, ptrdiff_t padding);
+ static char* SkipPod(char* footerEnd);
+ static void RunDtorsOnBlock(char* footerEnd);
+ static char* NextBlock(char* footerEnd);
- // N.B. Action is different than FooterAction. FooterAction expects the end of the Footer,
- // and returns the start of the object. An Action expects the end of the *Object* and returns
- // the start of the object.
- template<typename Action>
- void installIntFooter(ptrdiff_t size, ptrdiff_t padding) {
- if (SkTFitsIn<int32_t>(size)) {
- int32_t smallSize = static_cast<int32_t>(size);
- memmove(fCursor, &smallSize, sizeof(int32_t));
- fCursor += sizeof(int32_t);
- this->installFooter(
- [](char* footerEnd) {
- char* objEnd = footerEnd - (sizeof(Footer) + sizeof(int32_t));
- int32_t data;
- memmove(&data, objEnd, sizeof(int32_t));
- return Action()(objEnd, data);
- },
- padding);
- } else {
- memmove(fCursor, &size, sizeof(ptrdiff_t));
- fCursor += sizeof(ptrdiff_t);
- this->installFooter(
- [](char* footerEnd) {
- char* objEnd = footerEnd - (sizeof(Footer) + sizeof(ptrdiff_t));
- ptrdiff_t data;
- memmove(&data, objEnd, sizeof(ptrdiff_t));
- return Action()(objEnd, data);
- },
- padding);
- }
- }
+ void installFooter(FooterAction* releaser, ptrdiff_t padding);
+ void installUint32Footer(FooterAction* action, uint32_t value, ptrdiff_t padding);
+ void installPtrFooter(FooterAction* action, char* ptr, ptrdiff_t padding);
void ensureSpace(size_t size, size_t alignment);
@@ -157,48 +132,45 @@ private:
template <typename T>
char* commonArrayAlloc(size_t count) {
+ SkASSERT(SkTFitsIn<uint32_t>(count));
char* objStart;
size_t arraySize = count * sizeof(T);
- SkASSERT(arraySize > 0);
-
if (skstd::is_trivially_destructible<T>::value) {
objStart = this->allocObject(arraySize, alignof(T));
fCursor = objStart + arraySize;
} else {
- size_t countSize = SkTFitsIn<int32_t>(count) ? sizeof(int32_t) : sizeof(ptrdiff_t);
- size_t totalSize = arraySize + sizeof(Footer) + countSize;
+ size_t totalSize = arraySize + sizeof(Footer) + sizeof(uint32_t);
objStart = this->allocObjectWithFooter(totalSize, alignof(T));
size_t padding = objStart - fCursor;
// Advance to end of array to install footer.?
fCursor = objStart + arraySize;
- this->installIntFooter<ArrayDestructor<T>> (count, padding);
+ this->installUint32Footer(
+ [](char* footerEnd) {
+ char* objEnd = footerEnd - (sizeof(Footer) + sizeof(uint32_t));
+ uint32_t count;
+ memmove(&count, objEnd, sizeof(uint32_t));
+ char* objStart = objEnd - count * sizeof(T);
+ T* array = (T*) objStart;
+ for (uint32_t i = 0; i < count; i++) {
+ array[i].~T();
+ }
+ return objStart;
+ },
+ SkTo<uint32_t>(count),
+ padding);
}
return objStart;
}
- char* callFooterAction(char* end);
-
- static char* EndChain(char*);
-
- template<typename T>
- struct ArrayDestructor {
- char* operator()(char* objEnd, ptrdiff_t count) {
- char* objStart = objEnd - count * sizeof(T);
- T* array = (T*) objStart;
- for (int i = 0; i < count; i++) {
- array[i].~T();
- }
- return objStart;
- }
- };
-
- char* fDtorCursor;
- char* fCursor;
- char* fEnd;
- size_t fExtraSize;
+ char* fDtorCursor;
+ char* fCursor;
+ char* fEnd;
+ char* const fFirstBlock;
+ const size_t fFirstSize;
+ const size_t fExtraSize;
};
#endif//SkFixedAlloc_DEFINED
diff --git a/tests/ArenaAllocTest.cpp b/tests/ArenaAllocTest.cpp
index 647ea25283..0836b0c49f 100644
--- a/tests/ArenaAllocTest.cpp
+++ b/tests/ArenaAllocTest.cpp
@@ -26,6 +26,26 @@ namespace {
uint32_t array[128];
};
+ struct Node {
+ Node(Node* n) : next(n) { created++; }
+ ~Node() {
+ destroyed++;
+ if (next) {
+ next->~Node();
+ }
+ }
+ Node *next;
+ };
+
+ struct Start {
+ ~Start() {
+ if (start) {
+ start->~Node();
+ }
+ }
+ Node* start;
+ };
+
}
struct WithDtor {
@@ -63,7 +83,7 @@ DEF_TEST(ArenaAlloc, r) {
{
created = 0;
destroyed = 0;
- char block[1024];
+ char block[64];
SkArenaAlloc arena{block};
REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
@@ -113,4 +133,30 @@ DEF_TEST(ArenaAlloc, r) {
}
REPORTER_ASSERT(r, created == 11);
REPORTER_ASSERT(r, destroyed == 11);
+
+ {
+ char storage[64];
+ SkArenaAlloc arena{storage};
+ arena.makeArrayDefault<char>(256);
+ arena.reset();
+ arena.reset();
+ }
+
+ {
+ created = 0;
+ destroyed = 0;
+ char storage[64];
+ SkArenaAlloc arena{storage};
+
+ Start start;
+ Node* current = nullptr;
+ for (int i = 0; i < 128; i++) {
+ uint64_t* temp = arena.makeArrayDefault<uint64_t>(sizeof(Node) / sizeof(Node*));
+ current = new (temp)Node(current);
+ }
+ start.start = current;
+ }
+
+ REPORTER_ASSERT(r, created == 128);
+ REPORTER_ASSERT(r, destroyed == 128);
}