diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkFixedAlloc.cpp | 15 | ||||
-rw-r--r-- | src/core/SkFixedAlloc.h | 62 |
2 files changed, 48 insertions, 29 deletions
diff --git a/src/core/SkFixedAlloc.cpp b/src/core/SkFixedAlloc.cpp index 133245a9cb..cb2f798d4f 100644 --- a/src/core/SkFixedAlloc.cpp +++ b/src/core/SkFixedAlloc.cpp @@ -8,28 +8,29 @@ #include "SkFixedAlloc.h" SkFixedAlloc::SkFixedAlloc(void* ptr, size_t len) - : fBuffer((char*)ptr), fUsed(0), fLimit(len) {} + : fStorage((char*)ptr), fCursor(fStorage), fEnd(fStorage + len) {} void SkFixedAlloc::undo() { // This function is essentially make() in reverse. // First, read the Footer we stamped at the end. Footer footer; - memcpy(&footer, fBuffer + fUsed - sizeof(Footer), sizeof(Footer)); + memcpy(&footer, fCursor - sizeof(Footer), sizeof(Footer)); - // That tells us where the T starts and how to destroy it. - footer.dtor(fBuffer + fUsed - sizeof(Footer) - footer.len); + Releaser releaser = (Releaser)((char*)Base + (footer >> 5)); + ptrdiff_t padding = footer & 31; - // We can reuse bytes that stored the Footer, the T, and any that we skipped for alignment. - fUsed -= sizeof(Footer) + footer.len + footer.skip; + fCursor = releaser(fCursor); + fCursor -= padding; } void SkFixedAlloc::reset() { - while (fUsed) { + while (fCursor > fStorage) { this->undo(); } } +void SkFixedAlloc::Base() { } SkFallbackAlloc::SkFallbackAlloc(SkFixedAlloc* fixed) : fFixedAlloc(fixed) {} diff --git a/src/core/SkFixedAlloc.h b/src/core/SkFixedAlloc.h index cbf5ac25d4..4d148f9e93 100644 --- a/src/core/SkFixedAlloc.h +++ b/src/core/SkFixedAlloc.h @@ -21,31 +21,47 @@ public: ~SkFixedAlloc() { this->reset(); } // Allocates a new T in the buffer if possible. If not, returns nullptr. + // Assumptions: + // * max alignment value is 32 - if alignment is greater than 32, the allocation is best effort. + // * footer is 32 bits - 5 bits of alignment and 27 bits of deleter difference from Base. + // * deleter difference - the difference D is -2^26 <= D < 2^26. template <typename T, typename... Args> T* make(Args&&... args) { - auto aligned = ((uintptr_t)(fBuffer+fUsed) + alignof(T) - 1) & ~(alignof(T)-1); - size_t skip = aligned - (uintptr_t)(fBuffer+fUsed); + auto mask = alignof(T) - 1; - if (!SkTFitsIn<uint32_t>(skip) || - !SkTFitsIn<uint32_t>(sizeof(T)) || - fUsed + skip + sizeof(T) + sizeof(Footer) > fLimit) { + // Align fCursor for this allocation. + char* objStart = (char*)((uintptr_t)(fCursor + mask) & ~mask); + ptrdiff_t padding = objStart - fCursor; + Releaser releaser = [](char* objEnd) { + char* objStart = objEnd - (sizeof(T) + sizeof(Footer)); + ((T*)objStart)->~T(); + return objStart; + }; + + ptrdiff_t deleterDiff = (char*)releaser - (char*)Base; + + // TODO: combine both if statments when study is done. + if (objStart + sizeof(T) + sizeof(Footer) > fEnd) { return nullptr; } - // Skip ahead until our buffer is aligned for T. - fUsed += skip; + if (padding >= 32 + || deleterDiff >= (1 << 26) + || deleterDiff < -(1 << 26)) { + // Can't encode padding or deleter function offset. + SkDebugf("SkFixedAlloc - padding: %dt, deleteDiff: %dt\n", padding, deleterDiff); + SkFAIL("Failed to allocate due to constraint."); + return nullptr; + } - // Make space for T. - void* ptr = fBuffer+fUsed; - fUsed += sizeof(T); + // Advance cursor to end of the object. + fCursor = objStart + sizeof(T); - // Stamp a footer after the T that we can use to clean it up. - Footer footer = { [](void* ptr) { ((T*)ptr)->~T(); }, SkToU32(skip), SkToU32(sizeof(T)) }; - memcpy(fBuffer+fUsed, &footer, sizeof(Footer)); - fUsed += sizeof(Footer); + Footer footer = (Footer)(SkLeftShift((int64_t)deleterDiff, 5) | padding); + memcpy(fCursor, &footer, sizeof(Footer)); + fCursor += sizeof(Footer); - // Creating a T must be last for nesting to work. - return new (ptr) T(std::forward<Args>(args)...); + return new (objStart) T(std::forward<Args>(args)...); } // Destroys the last object allocated and frees its space in the buffer. @@ -55,13 +71,15 @@ public: void reset(); private: - struct Footer { - void (*dtor)(void*); - uint32_t skip, len; - }; + using Footer = int32_t; + using Releaser = char*(*)(char*); + + // A function pointer to use for offsets of releasers. + static void Base(); - char* fBuffer; - size_t fUsed, fLimit; + char* const fStorage; + char* fCursor; + char* const fEnd; }; class SkFallbackAlloc { |