1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2016 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkAutoMalloc_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define SkAutoMalloc_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAlign.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkNoncopyable.h" 15*c8dee2aaSAndroid Build Coastguard Worker 16*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 17*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 18*c8dee2aaSAndroid Build Coastguard Worker #include <memory> 19*c8dee2aaSAndroid Build Coastguard Worker 20*c8dee2aaSAndroid Build Coastguard Worker /** 21*c8dee2aaSAndroid Build Coastguard Worker * Manage an allocated block of heap memory. This object is the sole manager of 22*c8dee2aaSAndroid Build Coastguard Worker * the lifetime of the block, so the caller must not call sk_free() or delete 23*c8dee2aaSAndroid Build Coastguard Worker * on the block, unless release() was called. 24*c8dee2aaSAndroid Build Coastguard Worker */ 25*c8dee2aaSAndroid Build Coastguard Worker class SkAutoMalloc : SkNoncopyable { 26*c8dee2aaSAndroid Build Coastguard Worker public: 27*c8dee2aaSAndroid Build Coastguard Worker explicit SkAutoMalloc(size_t size = 0) 28*c8dee2aaSAndroid Build Coastguard Worker : fPtr(size ? sk_malloc_throw(size) : nullptr), fSize(size) {} 29*c8dee2aaSAndroid Build Coastguard Worker 30*c8dee2aaSAndroid Build Coastguard Worker /** 31*c8dee2aaSAndroid Build Coastguard Worker * Passed to reset to specify what happens if the requested size is smaller 32*c8dee2aaSAndroid Build Coastguard Worker * than the current size (and the current block was dynamically allocated). 33*c8dee2aaSAndroid Build Coastguard Worker */ 34*c8dee2aaSAndroid Build Coastguard Worker enum OnShrink { 35*c8dee2aaSAndroid Build Coastguard Worker /** 36*c8dee2aaSAndroid Build Coastguard Worker * If the requested size is smaller than the current size, and the 37*c8dee2aaSAndroid Build Coastguard Worker * current block is dynamically allocated, free the old block and 38*c8dee2aaSAndroid Build Coastguard Worker * malloc a new block of the smaller size. 39*c8dee2aaSAndroid Build Coastguard Worker */ 40*c8dee2aaSAndroid Build Coastguard Worker kAlloc_OnShrink, 41*c8dee2aaSAndroid Build Coastguard Worker 42*c8dee2aaSAndroid Build Coastguard Worker /** 43*c8dee2aaSAndroid Build Coastguard Worker * If the requested size is smaller than the current size, and the 44*c8dee2aaSAndroid Build Coastguard Worker * current block is dynamically allocated, just return the old 45*c8dee2aaSAndroid Build Coastguard Worker * block. 46*c8dee2aaSAndroid Build Coastguard Worker */ 47*c8dee2aaSAndroid Build Coastguard Worker kReuse_OnShrink 48*c8dee2aaSAndroid Build Coastguard Worker }; 49*c8dee2aaSAndroid Build Coastguard Worker 50*c8dee2aaSAndroid Build Coastguard Worker /** 51*c8dee2aaSAndroid Build Coastguard Worker * Reallocates the block to a new size. The ptr may or may not change. 52*c8dee2aaSAndroid Build Coastguard Worker */ 53*c8dee2aaSAndroid Build Coastguard Worker void* reset(size_t size = 0, OnShrink shrink = kAlloc_OnShrink) { 54*c8dee2aaSAndroid Build Coastguard Worker if (size != fSize && (size > fSize || kReuse_OnShrink != shrink)) { 55*c8dee2aaSAndroid Build Coastguard Worker fPtr.reset(size ? sk_malloc_throw(size) : nullptr); 56*c8dee2aaSAndroid Build Coastguard Worker fSize = size; 57*c8dee2aaSAndroid Build Coastguard Worker } 58*c8dee2aaSAndroid Build Coastguard Worker return fPtr.get(); 59*c8dee2aaSAndroid Build Coastguard Worker } 60*c8dee2aaSAndroid Build Coastguard Worker 61*c8dee2aaSAndroid Build Coastguard Worker /** 62*c8dee2aaSAndroid Build Coastguard Worker * Return the allocated block. 63*c8dee2aaSAndroid Build Coastguard Worker */ get()64*c8dee2aaSAndroid Build Coastguard Worker void* get() { return fPtr.get(); } get()65*c8dee2aaSAndroid Build Coastguard Worker const void* get() const { return fPtr.get(); } 66*c8dee2aaSAndroid Build Coastguard Worker 67*c8dee2aaSAndroid Build Coastguard Worker /** Transfer ownership of the current ptr to the caller, setting the 68*c8dee2aaSAndroid Build Coastguard Worker internal reference to null. Note the caller is reponsible for calling 69*c8dee2aaSAndroid Build Coastguard Worker sk_free on the returned address. 70*c8dee2aaSAndroid Build Coastguard Worker */ release()71*c8dee2aaSAndroid Build Coastguard Worker void* release() { 72*c8dee2aaSAndroid Build Coastguard Worker fSize = 0; 73*c8dee2aaSAndroid Build Coastguard Worker return fPtr.release(); 74*c8dee2aaSAndroid Build Coastguard Worker } 75*c8dee2aaSAndroid Build Coastguard Worker 76*c8dee2aaSAndroid Build Coastguard Worker private: 77*c8dee2aaSAndroid Build Coastguard Worker struct WrapFree { operatorWrapFree78*c8dee2aaSAndroid Build Coastguard Worker void operator()(void* p) { sk_free(p); } 79*c8dee2aaSAndroid Build Coastguard Worker }; 80*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<void, WrapFree> fPtr; 81*c8dee2aaSAndroid Build Coastguard Worker size_t fSize; // can be larger than the requested size (see kReuse) 82*c8dee2aaSAndroid Build Coastguard Worker }; 83*c8dee2aaSAndroid Build Coastguard Worker 84*c8dee2aaSAndroid Build Coastguard Worker /** 85*c8dee2aaSAndroid Build Coastguard Worker * Manage an allocated block of memory. If the requested size is <= kSizeRequested (or slightly 86*c8dee2aaSAndroid Build Coastguard Worker * more), then the allocation will come from the stack rather than the heap. This object is the 87*c8dee2aaSAndroid Build Coastguard Worker * sole manager of the lifetime of the block, so the caller must not call sk_free() or delete on 88*c8dee2aaSAndroid Build Coastguard Worker * the block. 89*c8dee2aaSAndroid Build Coastguard Worker */ 90*c8dee2aaSAndroid Build Coastguard Worker template <size_t kSizeRequested> class SkAutoSMalloc : SkNoncopyable { 91*c8dee2aaSAndroid Build Coastguard Worker public: 92*c8dee2aaSAndroid Build Coastguard Worker /** 93*c8dee2aaSAndroid Build Coastguard Worker * Creates initially empty storage. get() returns a ptr, but it is to a zero-byte allocation. 94*c8dee2aaSAndroid Build Coastguard Worker * Must call reset(size) to return an allocated block. 95*c8dee2aaSAndroid Build Coastguard Worker */ SkAutoSMalloc()96*c8dee2aaSAndroid Build Coastguard Worker SkAutoSMalloc() { 97*c8dee2aaSAndroid Build Coastguard Worker fPtr = fStorage; 98*c8dee2aaSAndroid Build Coastguard Worker fSize = kSize; 99*c8dee2aaSAndroid Build Coastguard Worker } 100*c8dee2aaSAndroid Build Coastguard Worker 101*c8dee2aaSAndroid Build Coastguard Worker /** 102*c8dee2aaSAndroid Build Coastguard Worker * Allocate a block of the specified size. If size <= kSizeRequested (or slightly more), then 103*c8dee2aaSAndroid Build Coastguard Worker * the allocation will come from the stack, otherwise it will be dynamically allocated. 104*c8dee2aaSAndroid Build Coastguard Worker */ SkAutoSMalloc(size_t size)105*c8dee2aaSAndroid Build Coastguard Worker explicit SkAutoSMalloc(size_t size) { 106*c8dee2aaSAndroid Build Coastguard Worker fPtr = fStorage; 107*c8dee2aaSAndroid Build Coastguard Worker fSize = kSize; 108*c8dee2aaSAndroid Build Coastguard Worker this->reset(size); 109*c8dee2aaSAndroid Build Coastguard Worker } 110*c8dee2aaSAndroid Build Coastguard Worker 111*c8dee2aaSAndroid Build Coastguard Worker /** 112*c8dee2aaSAndroid Build Coastguard Worker * Free the allocated block (if any). If the block was small enough to have been allocated on 113*c8dee2aaSAndroid Build Coastguard Worker * the stack, then this does nothing. 114*c8dee2aaSAndroid Build Coastguard Worker */ ~SkAutoSMalloc()115*c8dee2aaSAndroid Build Coastguard Worker ~SkAutoSMalloc() { 116*c8dee2aaSAndroid Build Coastguard Worker if (fPtr != (void*)fStorage) { 117*c8dee2aaSAndroid Build Coastguard Worker sk_free(fPtr); 118*c8dee2aaSAndroid Build Coastguard Worker } 119*c8dee2aaSAndroid Build Coastguard Worker } 120*c8dee2aaSAndroid Build Coastguard Worker 121*c8dee2aaSAndroid Build Coastguard Worker /** 122*c8dee2aaSAndroid Build Coastguard Worker * Return the allocated block. May return non-null even if the block is of zero size. Since 123*c8dee2aaSAndroid Build Coastguard Worker * this may be on the stack or dynamically allocated, the caller must not call sk_free() on it, 124*c8dee2aaSAndroid Build Coastguard Worker * but must rely on SkAutoSMalloc to manage it. 125*c8dee2aaSAndroid Build Coastguard Worker */ get()126*c8dee2aaSAndroid Build Coastguard Worker void* get() const { return fPtr; } 127*c8dee2aaSAndroid Build Coastguard Worker 128*c8dee2aaSAndroid Build Coastguard Worker /** 129*c8dee2aaSAndroid Build Coastguard Worker * Return a new block of the requested size, freeing (as necessary) any previously allocated 130*c8dee2aaSAndroid Build Coastguard Worker * block. As with the constructor, if size <= kSizeRequested (or slightly more) then the return 131*c8dee2aaSAndroid Build Coastguard Worker * block may be allocated locally, rather than from the heap. 132*c8dee2aaSAndroid Build Coastguard Worker */ 133*c8dee2aaSAndroid Build Coastguard Worker void* reset(size_t size, 134*c8dee2aaSAndroid Build Coastguard Worker SkAutoMalloc::OnShrink shrink = SkAutoMalloc::kAlloc_OnShrink, 135*c8dee2aaSAndroid Build Coastguard Worker bool* didChangeAlloc = nullptr) { 136*c8dee2aaSAndroid Build Coastguard Worker size = (size < kSize) ? kSize : size; 137*c8dee2aaSAndroid Build Coastguard Worker bool alloc = size != fSize && (SkAutoMalloc::kAlloc_OnShrink == shrink || size > fSize); 138*c8dee2aaSAndroid Build Coastguard Worker if (didChangeAlloc) { 139*c8dee2aaSAndroid Build Coastguard Worker *didChangeAlloc = alloc; 140*c8dee2aaSAndroid Build Coastguard Worker } 141*c8dee2aaSAndroid Build Coastguard Worker if (alloc) { 142*c8dee2aaSAndroid Build Coastguard Worker if (fPtr != (void*)fStorage) { 143*c8dee2aaSAndroid Build Coastguard Worker sk_free(fPtr); 144*c8dee2aaSAndroid Build Coastguard Worker } 145*c8dee2aaSAndroid Build Coastguard Worker 146*c8dee2aaSAndroid Build Coastguard Worker if (size == kSize) { 147*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fPtr != fStorage); // otherwise we lied when setting didChangeAlloc. 148*c8dee2aaSAndroid Build Coastguard Worker fPtr = fStorage; 149*c8dee2aaSAndroid Build Coastguard Worker } else { 150*c8dee2aaSAndroid Build Coastguard Worker fPtr = sk_malloc_throw(size); 151*c8dee2aaSAndroid Build Coastguard Worker } 152*c8dee2aaSAndroid Build Coastguard Worker 153*c8dee2aaSAndroid Build Coastguard Worker fSize = size; 154*c8dee2aaSAndroid Build Coastguard Worker } 155*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fSize >= size && fSize >= kSize); 156*c8dee2aaSAndroid Build Coastguard Worker SkASSERT((fPtr == fStorage) || fSize > kSize); 157*c8dee2aaSAndroid Build Coastguard Worker return fPtr; 158*c8dee2aaSAndroid Build Coastguard Worker } 159*c8dee2aaSAndroid Build Coastguard Worker 160*c8dee2aaSAndroid Build Coastguard Worker private: 161*c8dee2aaSAndroid Build Coastguard Worker // Align up to 32 bits. 162*c8dee2aaSAndroid Build Coastguard Worker static const size_t kSizeAlign4 = SkAlign4(kSizeRequested); 163*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_BUILD_FOR_GOOGLE3) 164*c8dee2aaSAndroid Build Coastguard Worker // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions 165*c8dee2aaSAndroid Build Coastguard Worker // have multiple large stack allocations. 166*c8dee2aaSAndroid Build Coastguard Worker static const size_t kMaxBytes = 4 * 1024; 167*c8dee2aaSAndroid Build Coastguard Worker static const size_t kSize = kSizeRequested > kMaxBytes ? kMaxBytes : kSizeAlign4; 168*c8dee2aaSAndroid Build Coastguard Worker #else 169*c8dee2aaSAndroid Build Coastguard Worker static const size_t kSize = kSizeAlign4; 170*c8dee2aaSAndroid Build Coastguard Worker #endif 171*c8dee2aaSAndroid Build Coastguard Worker 172*c8dee2aaSAndroid Build Coastguard Worker void* fPtr; 173*c8dee2aaSAndroid Build Coastguard Worker size_t fSize; // can be larger than the requested size (see kReuse) 174*c8dee2aaSAndroid Build Coastguard Worker uint32_t fStorage[kSize >> 2]; 175*c8dee2aaSAndroid Build Coastguard Worker }; 176*c8dee2aaSAndroid Build Coastguard Worker // Can't guard the constructor because it's a template class. 177*c8dee2aaSAndroid Build Coastguard Worker 178*c8dee2aaSAndroid Build Coastguard Worker #endif 179