[core] Allow SkArenaAlloc to query malloc() for usable size
When allocating memory with malloc(), allocators can provide a larger size than requested. SkArenaAlloc tries to guess what jemalloc would return, and align its allocation requests on the to-be-provided size. Some platforms (e.g. glibc or bionic with malloc_usable_size(), macOS with malloc_size()) can provide the actual value. This CL adds support to skia's malloc() wrappers to get this data, and to SkArenaAlloc to use it. Note that as is, this is a no-op in skia proper. Indeed, clients can (and do, for instance Chromium does) override sk_malloc() (and friends), so Skia cannot assume that sk_malloc() memory comes from malloc(). To implement this, a client needs to override sk_malloc_usable_size() to return the actual value. Bug: chromium:1335342 Change-Id: Id8ea177e9adccc9c4446fe379b6f05e726ea07ce Reviewed-on: https://skia-review.googlesource.com/c/skia/+/549516 Commit-Queue: Herb Derby <herb@google.com> Reviewed-by: Herb Derby <herb@google.com>
This commit is contained in:
parent
955b73beec
commit
916351bd6e
@ -78,6 +78,10 @@ SK_API extern void* sk_calloc_throw(size_t count, size_t elemSize);
|
||||
SK_API extern void* sk_malloc_throw(size_t count, size_t elemSize);
|
||||
SK_API extern void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize);
|
||||
|
||||
// Returns the true usable size provided by the underlying allocator, or 0 if
|
||||
// querying the allocation size is not supported.
|
||||
SK_API extern size_t sk_malloc_usable_size(void* buffer);
|
||||
|
||||
/**
|
||||
* These variants return nullptr on failure
|
||||
*/
|
||||
|
@ -5,6 +5,7 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/private/SkMalloc.h"
|
||||
#include "src/core/SkArenaAlloc.h"
|
||||
|
||||
#include <algorithm>
|
||||
@ -93,6 +94,13 @@ void SkArenaAlloc::ensureSpace(uint32_t size, uint32_t alignment) {
|
||||
}
|
||||
|
||||
char* newBlock = static_cast<char*>(sk_malloc_throw(allocationSize, 1));
|
||||
size_t actualAllocatedSize = sk_malloc_usable_size(newBlock);
|
||||
// 0 means that the allocated size is not available, don't change anything
|
||||
// then.
|
||||
if (actualAllocatedSize) {
|
||||
AssertRelease(actualAllocatedSize >= allocationSize);
|
||||
allocationSize = actualAllocatedSize;
|
||||
}
|
||||
|
||||
auto previousDtor = fDtorCursor;
|
||||
fCursor = newBlock;
|
||||
|
@ -20,3 +20,11 @@ void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize) {
|
||||
void* sk_malloc_canfail(size_t count, size_t elemSize) {
|
||||
return sk_malloc_canfail(SkSafeMath::Mul(count, elemSize));
|
||||
}
|
||||
|
||||
size_t sk_malloc_usable_size(void* buffer) {
|
||||
// Since sk_malloc() can be overridden by clients, there is no guarantee
|
||||
// that the memory allocated with it comes from malloc(). So the default
|
||||
// implementation can only return 0 to signal that generic support is not
|
||||
// possible.
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user