1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2020 Google LLC
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 SkBlockAllocator_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define SkBlockAllocator_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkASAN.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAlign.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMacros.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkNoncopyable.h"
18*c8dee2aaSAndroid Build Coastguard Worker
19*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
20*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
21*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
22*c8dee2aaSAndroid Build Coastguard Worker #include <limits>
23*c8dee2aaSAndroid Build Coastguard Worker #include <new>
24*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits>
25*c8dee2aaSAndroid Build Coastguard Worker
26*c8dee2aaSAndroid Build Coastguard Worker /**
27*c8dee2aaSAndroid Build Coastguard Worker * SkBlockAllocator provides low-level support for a block allocated arena with a dynamic tail that
28*c8dee2aaSAndroid Build Coastguard Worker * tracks space reservations within each block. Its APIs provide the ability to reserve space,
29*c8dee2aaSAndroid Build Coastguard Worker * resize reservations, and release reservations. It will automatically create new blocks if needed
30*c8dee2aaSAndroid Build Coastguard Worker * and destroy all remaining blocks when it is destructed. It assumes that anything allocated within
31*c8dee2aaSAndroid Build Coastguard Worker * its blocks has its destructors called externally. It is recommended that SkBlockAllocator is
32*c8dee2aaSAndroid Build Coastguard Worker * wrapped by a higher-level allocator that uses the low-level APIs to implement a simpler,
33*c8dee2aaSAndroid Build Coastguard Worker * purpose-focused API w/o having to worry as much about byte-level concerns.
34*c8dee2aaSAndroid Build Coastguard Worker *
35*c8dee2aaSAndroid Build Coastguard Worker * SkBlockAllocator has no limit to its total size, but each allocation is limited to 512MB (which
36*c8dee2aaSAndroid Build Coastguard Worker * should be sufficient for Skia's use cases). This upper allocation limit allows all internal
37*c8dee2aaSAndroid Build Coastguard Worker * operations to be performed using 'int' and avoid many overflow checks. Static asserts are used
38*c8dee2aaSAndroid Build Coastguard Worker * to ensure that those operations would not overflow when using the largest possible values.
39*c8dee2aaSAndroid Build Coastguard Worker *
40*c8dee2aaSAndroid Build Coastguard Worker * Possible use modes:
41*c8dee2aaSAndroid Build Coastguard Worker * 1. No upfront allocation, either on the stack or as a field
42*c8dee2aaSAndroid Build Coastguard Worker * SkBlockAllocator allocator(policy, heapAllocSize);
43*c8dee2aaSAndroid Build Coastguard Worker *
44*c8dee2aaSAndroid Build Coastguard Worker * 2. In-place new'd
45*c8dee2aaSAndroid Build Coastguard Worker * void* mem = operator new(totalSize);
46*c8dee2aaSAndroid Build Coastguard Worker * SkBlockAllocator* allocator = new (mem) SkBlockAllocator(policy, heapAllocSize,
47*c8dee2aaSAndroid Build Coastguard Worker * totalSize- sizeof(SkBlockAllocator));
48*c8dee2aaSAndroid Build Coastguard Worker * delete allocator;
49*c8dee2aaSAndroid Build Coastguard Worker *
50*c8dee2aaSAndroid Build Coastguard Worker * 3. Use SkSBlockAllocator to increase the preallocation size
51*c8dee2aaSAndroid Build Coastguard Worker * SkSBlockAllocator<1024> allocator(policy, heapAllocSize);
52*c8dee2aaSAndroid Build Coastguard Worker * sizeof(allocator) == 1024;
53*c8dee2aaSAndroid Build Coastguard Worker */
54*c8dee2aaSAndroid Build Coastguard Worker // TODO(michaelludwig) - While API is different, this shares similarities to SkArenaAlloc and
55*c8dee2aaSAndroid Build Coastguard Worker // SkFibBlockSizes, so we should work to integrate them.
56*c8dee2aaSAndroid Build Coastguard Worker class SkBlockAllocator final : SkNoncopyable {
57*c8dee2aaSAndroid Build Coastguard Worker public:
58*c8dee2aaSAndroid Build Coastguard Worker // Largest size that can be requested from allocate(), chosen because it's the largest pow-2
59*c8dee2aaSAndroid Build Coastguard Worker // that is less than int32_t::max()/2.
60*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kMaxAllocationSize = 1 << 29;
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker enum class GrowthPolicy : int {
63*c8dee2aaSAndroid Build Coastguard Worker kFixed, // Next block size = N
64*c8dee2aaSAndroid Build Coastguard Worker kLinear, // = #blocks * N
65*c8dee2aaSAndroid Build Coastguard Worker kFibonacci, // = fibonacci(#blocks) * N
66*c8dee2aaSAndroid Build Coastguard Worker kExponential, // = 2^#blocks * N
67*c8dee2aaSAndroid Build Coastguard Worker kLast = kExponential
68*c8dee2aaSAndroid Build Coastguard Worker };
69*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kGrowthPolicyCount = static_cast<int>(GrowthPolicy::kLast) + 1;
70*c8dee2aaSAndroid Build Coastguard Worker
71*c8dee2aaSAndroid Build Coastguard Worker class Block final {
72*c8dee2aaSAndroid Build Coastguard Worker public:
73*c8dee2aaSAndroid Build Coastguard Worker ~Block();
delete(void * p)74*c8dee2aaSAndroid Build Coastguard Worker void operator delete(void* p) { ::operator delete(p); }
75*c8dee2aaSAndroid Build Coastguard Worker
76*c8dee2aaSAndroid Build Coastguard Worker // Return the maximum allocation size with the given alignment that can fit in this block.
77*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align = 1, size_t Padding = 0>
avail()78*c8dee2aaSAndroid Build Coastguard Worker int avail() const { return std::max(0, fSize - this->cursor<Align, Padding>()); }
79*c8dee2aaSAndroid Build Coastguard Worker
80*c8dee2aaSAndroid Build Coastguard Worker // Return the aligned offset of the first allocation, assuming it was made with the
81*c8dee2aaSAndroid Build Coastguard Worker // specified Align, and Padding. The returned offset does not mean a valid allocation
82*c8dee2aaSAndroid Build Coastguard Worker // starts at that offset, this is a utility function for classes built on top to manage
83*c8dee2aaSAndroid Build Coastguard Worker // indexing into a block effectively.
84*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align = 1, size_t Padding = 0>
firstAlignedOffset()85*c8dee2aaSAndroid Build Coastguard Worker int firstAlignedOffset() const { return this->alignedOffset<Align, Padding>(kDataStart); }
86*c8dee2aaSAndroid Build Coastguard Worker
87*c8dee2aaSAndroid Build Coastguard Worker // Convert an offset into this block's storage into a usable pointer.
ptr(int offset)88*c8dee2aaSAndroid Build Coastguard Worker void* ptr(int offset) {
89*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(offset >= kDataStart && offset < fSize);
90*c8dee2aaSAndroid Build Coastguard Worker return reinterpret_cast<char*>(this) + offset;
91*c8dee2aaSAndroid Build Coastguard Worker }
ptr(int offset)92*c8dee2aaSAndroid Build Coastguard Worker const void* ptr(int offset) const { return const_cast<Block*>(this)->ptr(offset); }
93*c8dee2aaSAndroid Build Coastguard Worker
94*c8dee2aaSAndroid Build Coastguard Worker // Every block has an extra 'int' for clients to use however they want. It will start
95*c8dee2aaSAndroid Build Coastguard Worker // at 0 when a new block is made, or when the head block is reset.
metadata()96*c8dee2aaSAndroid Build Coastguard Worker int metadata() const { return fMetadata; }
setMetadata(int value)97*c8dee2aaSAndroid Build Coastguard Worker void setMetadata(int value) { fMetadata = value; }
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Worker /**
100*c8dee2aaSAndroid Build Coastguard Worker * Release the byte range between offset 'start' (inclusive) and 'end' (exclusive). This
101*c8dee2aaSAndroid Build Coastguard Worker * will return true if those bytes were successfully reclaimed, i.e. a subsequent allocation
102*c8dee2aaSAndroid Build Coastguard Worker * request could occupy the space. Regardless of return value, the provided byte range that
103*c8dee2aaSAndroid Build Coastguard Worker * [start, end) represents should not be used until it's re-allocated with allocate<...>().
104*c8dee2aaSAndroid Build Coastguard Worker */
105*c8dee2aaSAndroid Build Coastguard Worker inline bool release(int start, int end);
106*c8dee2aaSAndroid Build Coastguard Worker
107*c8dee2aaSAndroid Build Coastguard Worker /**
108*c8dee2aaSAndroid Build Coastguard Worker * Resize a previously reserved byte range of offset 'start' (inclusive) to 'end'
109*c8dee2aaSAndroid Build Coastguard Worker * (exclusive). 'deltaBytes' is the SIGNED change to length of the reservation.
110*c8dee2aaSAndroid Build Coastguard Worker *
111*c8dee2aaSAndroid Build Coastguard Worker * When negative this means the reservation is shrunk and the new length is (end - start -
112*c8dee2aaSAndroid Build Coastguard Worker * |deltaBytes|). If this new length would be 0, the byte range can no longer be used (as if
113*c8dee2aaSAndroid Build Coastguard Worker * it were released instead). Asserts that it would not shrink the reservation below 0.
114*c8dee2aaSAndroid Build Coastguard Worker *
115*c8dee2aaSAndroid Build Coastguard Worker * If 'deltaBytes' is positive, the allocator attempts to increase the length of the
116*c8dee2aaSAndroid Build Coastguard Worker * reservation. If 'deltaBytes' is less than or equal to avail() and it was the last
117*c8dee2aaSAndroid Build Coastguard Worker * allocation in the block, it can be resized. If there is not enough available bytes to
118*c8dee2aaSAndroid Build Coastguard Worker * accommodate the increase in size, or another allocation is blocking the increase in size,
119*c8dee2aaSAndroid Build Coastguard Worker * then false will be returned and the reserved byte range is unmodified.
120*c8dee2aaSAndroid Build Coastguard Worker */
121*c8dee2aaSAndroid Build Coastguard Worker inline bool resize(int start, int end, int deltaBytes);
122*c8dee2aaSAndroid Build Coastguard Worker
123*c8dee2aaSAndroid Build Coastguard Worker private:
124*c8dee2aaSAndroid Build Coastguard Worker friend class SkBlockAllocator;
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard Worker Block(Block* prev, int allocationSize);
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker // We poison the unallocated space in a Block to allow ASAN to catch invalid writes.
poisonRange(int start,int end)129*c8dee2aaSAndroid Build Coastguard Worker void poisonRange(int start, int end) {
130*c8dee2aaSAndroid Build Coastguard Worker sk_asan_poison_memory_region(reinterpret_cast<char*>(this) + start, end - start);
131*c8dee2aaSAndroid Build Coastguard Worker }
unpoisonRange(int start,int end)132*c8dee2aaSAndroid Build Coastguard Worker void unpoisonRange(int start, int end) {
133*c8dee2aaSAndroid Build Coastguard Worker sk_asan_unpoison_memory_region(reinterpret_cast<char*>(this) + start, end - start);
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker
136*c8dee2aaSAndroid Build Coastguard Worker // Get fCursor, but aligned such that ptr(rval) satisfies Align.
137*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align, size_t Padding>
cursor()138*c8dee2aaSAndroid Build Coastguard Worker int cursor() const { return this->alignedOffset<Align, Padding>(fCursor); }
139*c8dee2aaSAndroid Build Coastguard Worker
140*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align, size_t Padding>
141*c8dee2aaSAndroid Build Coastguard Worker int alignedOffset(int offset) const;
142*c8dee2aaSAndroid Build Coastguard Worker
isScratch()143*c8dee2aaSAndroid Build Coastguard Worker bool isScratch() const { return fCursor < 0; }
markAsScratch()144*c8dee2aaSAndroid Build Coastguard Worker void markAsScratch() {
145*c8dee2aaSAndroid Build Coastguard Worker fCursor = -1;
146*c8dee2aaSAndroid Build Coastguard Worker this->poisonRange(kDataStart, fSize);
147*c8dee2aaSAndroid Build Coastguard Worker }
148*c8dee2aaSAndroid Build Coastguard Worker
149*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(uint32_t fSentinel;) // known value to check for bad back pointers to blocks
150*c8dee2aaSAndroid Build Coastguard Worker
151*c8dee2aaSAndroid Build Coastguard Worker Block* fNext; // doubly-linked list of blocks
152*c8dee2aaSAndroid Build Coastguard Worker Block* fPrev;
153*c8dee2aaSAndroid Build Coastguard Worker
154*c8dee2aaSAndroid Build Coastguard Worker // Each block tracks its own cursor because as later blocks are released, an older block
155*c8dee2aaSAndroid Build Coastguard Worker // may become the active tail again.
156*c8dee2aaSAndroid Build Coastguard Worker int fSize; // includes the size of the BlockHeader and requested metadata
157*c8dee2aaSAndroid Build Coastguard Worker int fCursor; // (this + fCursor) points to next available allocation
158*c8dee2aaSAndroid Build Coastguard Worker int fMetadata;
159*c8dee2aaSAndroid Build Coastguard Worker
160*c8dee2aaSAndroid Build Coastguard Worker // On release builds, a Block's other 2 pointers and 3 int fields leaves 4 bytes of padding
161*c8dee2aaSAndroid Build Coastguard Worker // for 8 and 16 aligned systems. Currently this is only manipulated in the head block for
162*c8dee2aaSAndroid Build Coastguard Worker // an allocator-level metadata and is explicitly not reset when the head block is "released"
163*c8dee2aaSAndroid Build Coastguard Worker // Down the road we could instead choose to offer multiple metadata slots per block.
164*c8dee2aaSAndroid Build Coastguard Worker int fAllocatorMetadata;
165*c8dee2aaSAndroid Build Coastguard Worker };
166*c8dee2aaSAndroid Build Coastguard Worker
167*c8dee2aaSAndroid Build Coastguard Worker // Tuple representing a range of bytes, marking the unaligned start, the first aligned point
168*c8dee2aaSAndroid Build Coastguard Worker // after any padding, and the upper limit depending on requested size.
169*c8dee2aaSAndroid Build Coastguard Worker struct ByteRange {
170*c8dee2aaSAndroid Build Coastguard Worker Block* fBlock; // Owning block
171*c8dee2aaSAndroid Build Coastguard Worker int fStart; // Inclusive byte lower limit of byte range
172*c8dee2aaSAndroid Build Coastguard Worker int fAlignedOffset; // >= start, matching alignment requirement (i.e. first real byte)
173*c8dee2aaSAndroid Build Coastguard Worker int fEnd; // Exclusive upper limit of byte range
174*c8dee2aaSAndroid Build Coastguard Worker };
175*c8dee2aaSAndroid Build Coastguard Worker
176*c8dee2aaSAndroid Build Coastguard Worker // The size of the head block is determined by 'additionalPreallocBytes'. Subsequent heap blocks
177*c8dee2aaSAndroid Build Coastguard Worker // are determined by 'policy' and 'blockIncrementBytes', although 'blockIncrementBytes' will be
178*c8dee2aaSAndroid Build Coastguard Worker // aligned to std::max_align_t.
179*c8dee2aaSAndroid Build Coastguard Worker //
180*c8dee2aaSAndroid Build Coastguard Worker // When 'additionalPreallocBytes' > 0, the allocator assumes that many extra bytes immediately
181*c8dee2aaSAndroid Build Coastguard Worker // after the allocator can be used by its inline head block. This is useful when the allocator
182*c8dee2aaSAndroid Build Coastguard Worker // is in-place new'ed into a larger block of memory, but it should remain set to 0 if stack
183*c8dee2aaSAndroid Build Coastguard Worker // allocated or if the class layout does not guarantee that space is present.
184*c8dee2aaSAndroid Build Coastguard Worker SkBlockAllocator(GrowthPolicy policy, size_t blockIncrementBytes,
185*c8dee2aaSAndroid Build Coastguard Worker size_t additionalPreallocBytes = 0);
186*c8dee2aaSAndroid Build Coastguard Worker
~SkBlockAllocator()187*c8dee2aaSAndroid Build Coastguard Worker ~SkBlockAllocator() { this->reset(); }
delete(void * p)188*c8dee2aaSAndroid Build Coastguard Worker void operator delete(void* p) { ::operator delete(p); }
189*c8dee2aaSAndroid Build Coastguard Worker
190*c8dee2aaSAndroid Build Coastguard Worker /**
191*c8dee2aaSAndroid Build Coastguard Worker * Helper to calculate the minimum number of bytes needed for heap block size, under the
192*c8dee2aaSAndroid Build Coastguard Worker * assumption that Align will be the requested alignment of the first call to allocate().
193*c8dee2aaSAndroid Build Coastguard Worker * Ex. To store N instances of T in a heap block, the 'blockIncrementBytes' should be set to
194*c8dee2aaSAndroid Build Coastguard Worker * BlockOverhead<alignof(T)>() + N * sizeof(T) when making the SkBlockAllocator.
195*c8dee2aaSAndroid Build Coastguard Worker */
196*c8dee2aaSAndroid Build Coastguard Worker template<size_t Align = 1, size_t Padding = 0>
197*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t BlockOverhead();
198*c8dee2aaSAndroid Build Coastguard Worker
199*c8dee2aaSAndroid Build Coastguard Worker /**
200*c8dee2aaSAndroid Build Coastguard Worker * Helper to calculate the minimum number of bytes needed for a preallocation, under the
201*c8dee2aaSAndroid Build Coastguard Worker * assumption that Align will be the requested alignment of the first call to allocate().
202*c8dee2aaSAndroid Build Coastguard Worker * Ex. To preallocate a SkSBlockAllocator to hold N instances of T, its arge should be
203*c8dee2aaSAndroid Build Coastguard Worker * Overhead<alignof(T)>() + N * sizeof(T)
204*c8dee2aaSAndroid Build Coastguard Worker */
205*c8dee2aaSAndroid Build Coastguard Worker template<size_t Align = 1, size_t Padding = 0>
206*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t Overhead();
207*c8dee2aaSAndroid Build Coastguard Worker
208*c8dee2aaSAndroid Build Coastguard Worker /**
209*c8dee2aaSAndroid Build Coastguard Worker * Return the total number of bytes of the allocator, including its instance overhead, per-block
210*c8dee2aaSAndroid Build Coastguard Worker * overhead and space used for allocations.
211*c8dee2aaSAndroid Build Coastguard Worker */
212*c8dee2aaSAndroid Build Coastguard Worker size_t totalSize() const;
213*c8dee2aaSAndroid Build Coastguard Worker /**
214*c8dee2aaSAndroid Build Coastguard Worker * Return the total number of bytes usable for allocations. This includes bytes that have
215*c8dee2aaSAndroid Build Coastguard Worker * been reserved already by a call to allocate() and bytes that are still available. It is
216*c8dee2aaSAndroid Build Coastguard Worker * totalSize() minus all allocator and block-level overhead.
217*c8dee2aaSAndroid Build Coastguard Worker */
218*c8dee2aaSAndroid Build Coastguard Worker size_t totalUsableSpace() const;
219*c8dee2aaSAndroid Build Coastguard Worker /**
220*c8dee2aaSAndroid Build Coastguard Worker * Return the total number of usable bytes that have been reserved by allocations. This will
221*c8dee2aaSAndroid Build Coastguard Worker * be less than or equal to totalUsableSpace().
222*c8dee2aaSAndroid Build Coastguard Worker */
223*c8dee2aaSAndroid Build Coastguard Worker size_t totalSpaceInUse() const;
224*c8dee2aaSAndroid Build Coastguard Worker
225*c8dee2aaSAndroid Build Coastguard Worker /**
226*c8dee2aaSAndroid Build Coastguard Worker * Return the total number of bytes that were pre-allocated for the SkBlockAllocator. This will
227*c8dee2aaSAndroid Build Coastguard Worker * include 'additionalPreallocBytes' passed to the constructor, and represents what the total
228*c8dee2aaSAndroid Build Coastguard Worker * size would become after a call to reset().
229*c8dee2aaSAndroid Build Coastguard Worker */
preallocSize()230*c8dee2aaSAndroid Build Coastguard Worker size_t preallocSize() const {
231*c8dee2aaSAndroid Build Coastguard Worker // Don't double count fHead's Block overhead in both sizeof(SkBlockAllocator) and fSize.
232*c8dee2aaSAndroid Build Coastguard Worker return sizeof(SkBlockAllocator) + fHead.fSize - BaseHeadBlockSize();
233*c8dee2aaSAndroid Build Coastguard Worker }
234*c8dee2aaSAndroid Build Coastguard Worker /**
235*c8dee2aaSAndroid Build Coastguard Worker * Return the usable size of the inline head block; this will be equal to
236*c8dee2aaSAndroid Build Coastguard Worker * 'additionalPreallocBytes' plus any alignment padding that the system had to add to Block.
237*c8dee2aaSAndroid Build Coastguard Worker * The returned value represents what could be allocated before a heap block is be created.
238*c8dee2aaSAndroid Build Coastguard Worker */
preallocUsableSpace()239*c8dee2aaSAndroid Build Coastguard Worker size_t preallocUsableSpace() const {
240*c8dee2aaSAndroid Build Coastguard Worker return fHead.fSize - kDataStart;
241*c8dee2aaSAndroid Build Coastguard Worker }
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker /**
244*c8dee2aaSAndroid Build Coastguard Worker * Get the current value of the allocator-level metadata (a user-oriented slot). This is
245*c8dee2aaSAndroid Build Coastguard Worker * separate from any block-level metadata, but can serve a similar purpose to compactly support
246*c8dee2aaSAndroid Build Coastguard Worker * data collections on top of SkBlockAllocator.
247*c8dee2aaSAndroid Build Coastguard Worker */
metadata()248*c8dee2aaSAndroid Build Coastguard Worker int metadata() const { return fHead.fAllocatorMetadata; }
249*c8dee2aaSAndroid Build Coastguard Worker
250*c8dee2aaSAndroid Build Coastguard Worker /**
251*c8dee2aaSAndroid Build Coastguard Worker * Set the current value of the allocator-level metadata.
252*c8dee2aaSAndroid Build Coastguard Worker */
setMetadata(int value)253*c8dee2aaSAndroid Build Coastguard Worker void setMetadata(int value) { fHead.fAllocatorMetadata = value; }
254*c8dee2aaSAndroid Build Coastguard Worker
255*c8dee2aaSAndroid Build Coastguard Worker /**
256*c8dee2aaSAndroid Build Coastguard Worker * Reserve space that will hold 'size' bytes. This will automatically allocate a new block if
257*c8dee2aaSAndroid Build Coastguard Worker * there is not enough available space in the current block to provide 'size' bytes. The
258*c8dee2aaSAndroid Build Coastguard Worker * returned ByteRange tuple specifies the Block owning the reserved memory, the full byte range,
259*c8dee2aaSAndroid Build Coastguard Worker * and the aligned offset within that range to use for the user-facing pointer. The following
260*c8dee2aaSAndroid Build Coastguard Worker * invariants hold:
261*c8dee2aaSAndroid Build Coastguard Worker *
262*c8dee2aaSAndroid Build Coastguard Worker * 1. block->ptr(alignedOffset) is aligned to Align
263*c8dee2aaSAndroid Build Coastguard Worker * 2. end - alignedOffset == size
264*c8dee2aaSAndroid Build Coastguard Worker * 3. Padding <= alignedOffset - start <= Padding + Align - 1
265*c8dee2aaSAndroid Build Coastguard Worker *
266*c8dee2aaSAndroid Build Coastguard Worker * Invariant #3, when Padding > 0, allows intermediate allocators to embed metadata along with
267*c8dee2aaSAndroid Build Coastguard Worker * the allocations. If the Padding bytes are used for some 'struct Meta', then
268*c8dee2aaSAndroid Build Coastguard Worker * ptr(alignedOffset - sizeof(Meta)) can be safely used as a Meta* if Meta's alignment
269*c8dee2aaSAndroid Build Coastguard Worker * requirements are less than or equal to the alignment specified in allocate<>. This can be
270*c8dee2aaSAndroid Build Coastguard Worker * easily guaranteed by using the pattern:
271*c8dee2aaSAndroid Build Coastguard Worker *
272*c8dee2aaSAndroid Build Coastguard Worker * allocate<max(UserAlign, alignof(Meta)), sizeof(Meta)>(userSize);
273*c8dee2aaSAndroid Build Coastguard Worker *
274*c8dee2aaSAndroid Build Coastguard Worker * This ensures that ptr(alignedOffset) will always satisfy UserAlign and
275*c8dee2aaSAndroid Build Coastguard Worker * ptr(alignedOffset - sizeof(Meta)) will always satisfy alignof(Meta). Alternatively, memcpy
276*c8dee2aaSAndroid Build Coastguard Worker * can be used to read and write values between start and alignedOffset without worrying about
277*c8dee2aaSAndroid Build Coastguard Worker * alignment requirements of the metadata.
278*c8dee2aaSAndroid Build Coastguard Worker *
279*c8dee2aaSAndroid Build Coastguard Worker * For over-aligned allocations, the alignedOffset (as an int) may not be a multiple of Align,
280*c8dee2aaSAndroid Build Coastguard Worker * but the result of ptr(alignedOffset) will be a multiple of Align.
281*c8dee2aaSAndroid Build Coastguard Worker */
282*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align, size_t Padding = 0>
283*c8dee2aaSAndroid Build Coastguard Worker ByteRange allocate(size_t size);
284*c8dee2aaSAndroid Build Coastguard Worker
285*c8dee2aaSAndroid Build Coastguard Worker enum ReserveFlags : unsigned {
286*c8dee2aaSAndroid Build Coastguard Worker // If provided to reserve(), the input 'size' will be rounded up to the next size determined
287*c8dee2aaSAndroid Build Coastguard Worker // by the growth policy of the SkBlockAllocator. If not, 'size' will be aligned to max_align
288*c8dee2aaSAndroid Build Coastguard Worker kIgnoreGrowthPolicy_Flag = 0b01,
289*c8dee2aaSAndroid Build Coastguard Worker // If provided to reserve(), the number of available bytes of the current block will not
290*c8dee2aaSAndroid Build Coastguard Worker // be used to satisfy the reservation (assuming the contiguous range was long enough to
291*c8dee2aaSAndroid Build Coastguard Worker // begin with).
292*c8dee2aaSAndroid Build Coastguard Worker kIgnoreExistingBytes_Flag = 0b10,
293*c8dee2aaSAndroid Build Coastguard Worker
294*c8dee2aaSAndroid Build Coastguard Worker kNo_ReserveFlags = 0b00
295*c8dee2aaSAndroid Build Coastguard Worker };
296*c8dee2aaSAndroid Build Coastguard Worker
297*c8dee2aaSAndroid Build Coastguard Worker /**
298*c8dee2aaSAndroid Build Coastguard Worker * Ensure the block allocator has 'size' contiguous available bytes. After calling this
299*c8dee2aaSAndroid Build Coastguard Worker * function, currentBlock()->avail<Align, Padding>() may still report less than 'size' if the
300*c8dee2aaSAndroid Build Coastguard Worker * reserved space was added as a scratch block. This is done so that anything remaining in
301*c8dee2aaSAndroid Build Coastguard Worker * the current block can still be used if a smaller-than-size allocation is requested. If 'size'
302*c8dee2aaSAndroid Build Coastguard Worker * is requested by a subsequent allocation, the scratch block will automatically be activated
303*c8dee2aaSAndroid Build Coastguard Worker * and the request will not itself trigger any malloc.
304*c8dee2aaSAndroid Build Coastguard Worker *
305*c8dee2aaSAndroid Build Coastguard Worker * The optional 'flags' controls how the input size is allocated; by default it will attempt
306*c8dee2aaSAndroid Build Coastguard Worker * to use available contiguous bytes in the current block and will respect the growth policy
307*c8dee2aaSAndroid Build Coastguard Worker * of the allocator.
308*c8dee2aaSAndroid Build Coastguard Worker */
309*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align = 1, size_t Padding = 0>
310*c8dee2aaSAndroid Build Coastguard Worker void reserve(size_t size, ReserveFlags flags = kNo_ReserveFlags);
311*c8dee2aaSAndroid Build Coastguard Worker
312*c8dee2aaSAndroid Build Coastguard Worker /**
313*c8dee2aaSAndroid Build Coastguard Worker * Return a pointer to the start of the current block. This will never be null.
314*c8dee2aaSAndroid Build Coastguard Worker */
currentBlock()315*c8dee2aaSAndroid Build Coastguard Worker const Block* currentBlock() const { return fTail; }
currentBlock()316*c8dee2aaSAndroid Build Coastguard Worker Block* currentBlock() { return fTail; }
317*c8dee2aaSAndroid Build Coastguard Worker
headBlock()318*c8dee2aaSAndroid Build Coastguard Worker const Block* headBlock() const { return &fHead; }
headBlock()319*c8dee2aaSAndroid Build Coastguard Worker Block* headBlock() { return &fHead; }
320*c8dee2aaSAndroid Build Coastguard Worker
321*c8dee2aaSAndroid Build Coastguard Worker /**
322*c8dee2aaSAndroid Build Coastguard Worker * Return the block that owns the allocated 'ptr'. Assuming that earlier, an allocation was
323*c8dee2aaSAndroid Build Coastguard Worker * returned as {b, start, alignedOffset, end}, and 'p = b->ptr(alignedOffset)', then a call
324*c8dee2aaSAndroid Build Coastguard Worker * to 'owningBlock<Align, Padding>(p, start) == b'.
325*c8dee2aaSAndroid Build Coastguard Worker *
326*c8dee2aaSAndroid Build Coastguard Worker * If calling code has already made a pointer to their metadata, i.e. 'm = p - Padding', then
327*c8dee2aaSAndroid Build Coastguard Worker * 'owningBlock<Align, 0>(m, start)' will also return b, allowing you to recover the block from
328*c8dee2aaSAndroid Build Coastguard Worker * the metadata pointer.
329*c8dee2aaSAndroid Build Coastguard Worker *
330*c8dee2aaSAndroid Build Coastguard Worker * If calling code has access to the original alignedOffset, this function should not be used
331*c8dee2aaSAndroid Build Coastguard Worker * since the owning block is just 'p - alignedOffset', regardless of original Align or Padding.
332*c8dee2aaSAndroid Build Coastguard Worker */
333*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align, size_t Padding = 0>
334*c8dee2aaSAndroid Build Coastguard Worker Block* owningBlock(const void* ptr, int start);
335*c8dee2aaSAndroid Build Coastguard Worker
336*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align, size_t Padding = 0>
owningBlock(const void * ptr,int start)337*c8dee2aaSAndroid Build Coastguard Worker const Block* owningBlock(const void* ptr, int start) const {
338*c8dee2aaSAndroid Build Coastguard Worker return const_cast<SkBlockAllocator*>(this)->owningBlock<Align, Padding>(ptr, start);
339*c8dee2aaSAndroid Build Coastguard Worker }
340*c8dee2aaSAndroid Build Coastguard Worker
341*c8dee2aaSAndroid Build Coastguard Worker /**
342*c8dee2aaSAndroid Build Coastguard Worker * Find the owning block of the allocated pointer, 'p'. Without any additional information this
343*c8dee2aaSAndroid Build Coastguard Worker * is O(N) on the number of allocated blocks.
344*c8dee2aaSAndroid Build Coastguard Worker */
345*c8dee2aaSAndroid Build Coastguard Worker Block* findOwningBlock(const void* ptr);
findOwningBlock(const void * ptr)346*c8dee2aaSAndroid Build Coastguard Worker const Block* findOwningBlock(const void* ptr) const {
347*c8dee2aaSAndroid Build Coastguard Worker return const_cast<SkBlockAllocator*>(this)->findOwningBlock(ptr);
348*c8dee2aaSAndroid Build Coastguard Worker }
349*c8dee2aaSAndroid Build Coastguard Worker
350*c8dee2aaSAndroid Build Coastguard Worker /**
351*c8dee2aaSAndroid Build Coastguard Worker * Explicitly free an entire block, invalidating any remaining allocations from the block.
352*c8dee2aaSAndroid Build Coastguard Worker * SkBlockAllocator will release all alive blocks automatically when it is destroyed, but this
353*c8dee2aaSAndroid Build Coastguard Worker * function can be used to reclaim memory over the lifetime of the allocator. The provided
354*c8dee2aaSAndroid Build Coastguard Worker * 'block' pointer must have previously come from a call to currentBlock() or allocate().
355*c8dee2aaSAndroid Build Coastguard Worker *
356*c8dee2aaSAndroid Build Coastguard Worker * If 'block' represents the inline-allocated head block, its cursor and metadata are instead
357*c8dee2aaSAndroid Build Coastguard Worker * reset to their defaults.
358*c8dee2aaSAndroid Build Coastguard Worker *
359*c8dee2aaSAndroid Build Coastguard Worker * If the block is not the head block, it may be kept as a scratch block to be reused for
360*c8dee2aaSAndroid Build Coastguard Worker * subsequent allocation requests, instead of making an entirely new block. A scratch block is
361*c8dee2aaSAndroid Build Coastguard Worker * not visible when iterating over blocks but is reported in the total size of the allocator.
362*c8dee2aaSAndroid Build Coastguard Worker */
363*c8dee2aaSAndroid Build Coastguard Worker void releaseBlock(Block* block);
364*c8dee2aaSAndroid Build Coastguard Worker
365*c8dee2aaSAndroid Build Coastguard Worker /**
366*c8dee2aaSAndroid Build Coastguard Worker * Detach every heap-allocated block owned by 'other' and concatenate them to this allocator's
367*c8dee2aaSAndroid Build Coastguard Worker * list of blocks. This memory is now managed by this allocator. Since this only transfers
368*c8dee2aaSAndroid Build Coastguard Worker * ownership of a Block, and a Block itself does not move, any previous allocations remain
369*c8dee2aaSAndroid Build Coastguard Worker * valid and associated with their original Block instances. SkBlockAllocator-level functions
370*c8dee2aaSAndroid Build Coastguard Worker * that accept allocated pointers (e.g. findOwningBlock), must now use this allocator and not
371*c8dee2aaSAndroid Build Coastguard Worker * 'other' for these allocations.
372*c8dee2aaSAndroid Build Coastguard Worker *
373*c8dee2aaSAndroid Build Coastguard Worker * The head block of 'other' cannot be stolen, so higher-level allocators and memory structures
374*c8dee2aaSAndroid Build Coastguard Worker * must handle that data differently.
375*c8dee2aaSAndroid Build Coastguard Worker */
376*c8dee2aaSAndroid Build Coastguard Worker void stealHeapBlocks(SkBlockAllocator* other);
377*c8dee2aaSAndroid Build Coastguard Worker
378*c8dee2aaSAndroid Build Coastguard Worker /**
379*c8dee2aaSAndroid Build Coastguard Worker * Explicitly free all blocks (invalidating all allocations), and resets the head block to its
380*c8dee2aaSAndroid Build Coastguard Worker * default state. The allocator-level metadata is reset to 0 as well.
381*c8dee2aaSAndroid Build Coastguard Worker */
382*c8dee2aaSAndroid Build Coastguard Worker void reset();
383*c8dee2aaSAndroid Build Coastguard Worker
384*c8dee2aaSAndroid Build Coastguard Worker /**
385*c8dee2aaSAndroid Build Coastguard Worker * Remove any reserved scratch space, either from calling reserve() or releaseBlock().
386*c8dee2aaSAndroid Build Coastguard Worker */
387*c8dee2aaSAndroid Build Coastguard Worker void resetScratchSpace();
388*c8dee2aaSAndroid Build Coastguard Worker
389*c8dee2aaSAndroid Build Coastguard Worker template <bool Forward, bool Const> class BlockIter;
390*c8dee2aaSAndroid Build Coastguard Worker
391*c8dee2aaSAndroid Build Coastguard Worker /**
392*c8dee2aaSAndroid Build Coastguard Worker * Clients can iterate over all active Blocks in the SkBlockAllocator using for loops:
393*c8dee2aaSAndroid Build Coastguard Worker *
394*c8dee2aaSAndroid Build Coastguard Worker * Forward iteration from head to tail block (or non-const variant):
395*c8dee2aaSAndroid Build Coastguard Worker * for (const Block* b : this->blocks()) { }
396*c8dee2aaSAndroid Build Coastguard Worker * Reverse iteration from tail to head block:
397*c8dee2aaSAndroid Build Coastguard Worker * for (const Block* b : this->rblocks()) { }
398*c8dee2aaSAndroid Build Coastguard Worker *
399*c8dee2aaSAndroid Build Coastguard Worker * It is safe to call releaseBlock() on the active block while looping.
400*c8dee2aaSAndroid Build Coastguard Worker */
401*c8dee2aaSAndroid Build Coastguard Worker inline BlockIter<true, false> blocks();
402*c8dee2aaSAndroid Build Coastguard Worker inline BlockIter<true, true> blocks() const;
403*c8dee2aaSAndroid Build Coastguard Worker inline BlockIter<false, false> rblocks();
404*c8dee2aaSAndroid Build Coastguard Worker inline BlockIter<false, true> rblocks() const;
405*c8dee2aaSAndroid Build Coastguard Worker
406*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
407*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr uint32_t kAssignedMarker = 0xBEEFFACE;
408*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr uint32_t kFreedMarker = 0xCAFEBABE;
409*c8dee2aaSAndroid Build Coastguard Worker
410*c8dee2aaSAndroid Build Coastguard Worker void validate() const;
411*c8dee2aaSAndroid Build Coastguard Worker #endif
412*c8dee2aaSAndroid Build Coastguard Worker
413*c8dee2aaSAndroid Build Coastguard Worker private:
414*c8dee2aaSAndroid Build Coastguard Worker friend class BlockAllocatorTestAccess;
415*c8dee2aaSAndroid Build Coastguard Worker friend class TBlockListTestAccess;
416*c8dee2aaSAndroid Build Coastguard Worker
417*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kDataStart = sizeof(Block);
418*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_FORCE_8_BYTE_ALIGNMENT
419*c8dee2aaSAndroid Build Coastguard Worker // This is an issue for WASM builds using emscripten, which had std::max_align_t = 16, but
420*c8dee2aaSAndroid Build Coastguard Worker // was returning pointers only aligned to 8 bytes.
421*c8dee2aaSAndroid Build Coastguard Worker // https://github.com/emscripten-core/emscripten/issues/10072
422*c8dee2aaSAndroid Build Coastguard Worker //
423*c8dee2aaSAndroid Build Coastguard Worker // Setting this to 8 will let SkBlockAllocator properly correct for the pointer address if
424*c8dee2aaSAndroid Build Coastguard Worker // a 16-byte aligned allocation is requested in wasm (unlikely since we don't use long
425*c8dee2aaSAndroid Build Coastguard Worker // doubles).
426*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t kAddressAlign = 8;
427*c8dee2aaSAndroid Build Coastguard Worker #else
428*c8dee2aaSAndroid Build Coastguard Worker // The alignment Block addresses will be at when created using operator new
429*c8dee2aaSAndroid Build Coastguard Worker // (spec-compliant is pointers are aligned to max_align_t).
430*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t kAddressAlign = alignof(std::max_align_t);
431*c8dee2aaSAndroid Build Coastguard Worker #endif
432*c8dee2aaSAndroid Build Coastguard Worker
433*c8dee2aaSAndroid Build Coastguard Worker // Calculates the size of a new Block required to store a kMaxAllocationSize request for the
434*c8dee2aaSAndroid Build Coastguard Worker // given alignment and padding bytes. Also represents maximum valid fCursor value in a Block.
435*c8dee2aaSAndroid Build Coastguard Worker template<size_t Align, size_t Padding>
436*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t MaxBlockSize();
437*c8dee2aaSAndroid Build Coastguard Worker
BaseHeadBlockSize()438*c8dee2aaSAndroid Build Coastguard Worker static constexpr int BaseHeadBlockSize() {
439*c8dee2aaSAndroid Build Coastguard Worker return sizeof(SkBlockAllocator) - offsetof(SkBlockAllocator, fHead);
440*c8dee2aaSAndroid Build Coastguard Worker }
441*c8dee2aaSAndroid Build Coastguard Worker
442*c8dee2aaSAndroid Build Coastguard Worker // Append a new block to the end of the block linked list, updating fTail. 'minSize' must
443*c8dee2aaSAndroid Build Coastguard Worker // have enough room for sizeof(Block). 'maxSize' is the upper limit of fSize for the new block
444*c8dee2aaSAndroid Build Coastguard Worker // that will preserve the static guarantees SkBlockAllocator makes.
445*c8dee2aaSAndroid Build Coastguard Worker void addBlock(int minSize, int maxSize);
446*c8dee2aaSAndroid Build Coastguard Worker
scratchBlockSize()447*c8dee2aaSAndroid Build Coastguard Worker int scratchBlockSize() const { return fHead.fPrev ? fHead.fPrev->fSize : 0; }
448*c8dee2aaSAndroid Build Coastguard Worker
449*c8dee2aaSAndroid Build Coastguard Worker Block* fTail; // All non-head blocks are heap allocated; tail will never be null.
450*c8dee2aaSAndroid Build Coastguard Worker
451*c8dee2aaSAndroid Build Coastguard Worker // All remaining state is packed into 64 bits to keep SkBlockAllocator at 16 bytes + head block
452*c8dee2aaSAndroid Build Coastguard Worker // (on a 64-bit system).
453*c8dee2aaSAndroid Build Coastguard Worker
454*c8dee2aaSAndroid Build Coastguard Worker // Growth of the block size is controlled by four factors: BlockIncrement, N0 and N1, and a
455*c8dee2aaSAndroid Build Coastguard Worker // policy defining how N0 is updated. When a new block is needed, we calculate N1' = N0 + N1.
456*c8dee2aaSAndroid Build Coastguard Worker // Depending on the policy, N0' = N0 (no growth or linear growth), or N0' = N1 (Fibonacci), or
457*c8dee2aaSAndroid Build Coastguard Worker // N0' = N1' (exponential). The size of the new block is N1' * BlockIncrement * MaxAlign,
458*c8dee2aaSAndroid Build Coastguard Worker // after which fN0 and fN1 store N0' and N1' clamped into 23 bits. With current bit allocations,
459*c8dee2aaSAndroid Build Coastguard Worker // N1' is limited to 2^24, and assuming MaxAlign=16, then BlockIncrement must be '2' in order to
460*c8dee2aaSAndroid Build Coastguard Worker // eventually reach the hard 2^29 size limit of SkBlockAllocator.
461*c8dee2aaSAndroid Build Coastguard Worker
462*c8dee2aaSAndroid Build Coastguard Worker // Next heap block size = (fBlockIncrement * alignof(std::max_align_t) * (fN0 + fN1))
463*c8dee2aaSAndroid Build Coastguard Worker uint64_t fBlockIncrement : 16;
464*c8dee2aaSAndroid Build Coastguard Worker uint64_t fGrowthPolicy : 2; // GrowthPolicy
465*c8dee2aaSAndroid Build Coastguard Worker uint64_t fN0 : 23; // = 1 for linear/exp.; = 0 for fixed/fibonacci, initially
466*c8dee2aaSAndroid Build Coastguard Worker uint64_t fN1 : 23; // = 1 initially
467*c8dee2aaSAndroid Build Coastguard Worker
468*c8dee2aaSAndroid Build Coastguard Worker // Inline head block, must be at the end so that it can utilize any additional reserved space
469*c8dee2aaSAndroid Build Coastguard Worker // from the initial allocation.
470*c8dee2aaSAndroid Build Coastguard Worker // The head block's prev pointer may be non-null, which signifies a scratch block that may be
471*c8dee2aaSAndroid Build Coastguard Worker // reused instead of allocating an entirely new block (this helps when allocate+release calls
472*c8dee2aaSAndroid Build Coastguard Worker // bounce back and forth across the capacity of a block).
473*c8dee2aaSAndroid Build Coastguard Worker alignas(kAddressAlign) Block fHead;
474*c8dee2aaSAndroid Build Coastguard Worker
475*c8dee2aaSAndroid Build Coastguard Worker static_assert(kGrowthPolicyCount <= 4);
476*c8dee2aaSAndroid Build Coastguard Worker };
477*c8dee2aaSAndroid Build Coastguard Worker
478*c8dee2aaSAndroid Build Coastguard Worker // A wrapper around SkBlockAllocator that includes preallocated storage for the head block.
479*c8dee2aaSAndroid Build Coastguard Worker // N will be the preallocSize() reported by the allocator.
480*c8dee2aaSAndroid Build Coastguard Worker template<size_t N>
481*c8dee2aaSAndroid Build Coastguard Worker class SkSBlockAllocator : SkNoncopyable {
482*c8dee2aaSAndroid Build Coastguard Worker public:
483*c8dee2aaSAndroid Build Coastguard Worker using GrowthPolicy = SkBlockAllocator::GrowthPolicy;
484*c8dee2aaSAndroid Build Coastguard Worker
SkSBlockAllocator()485*c8dee2aaSAndroid Build Coastguard Worker SkSBlockAllocator() {
486*c8dee2aaSAndroid Build Coastguard Worker new (fStorage) SkBlockAllocator(GrowthPolicy::kFixed, N, N - sizeof(SkBlockAllocator));
487*c8dee2aaSAndroid Build Coastguard Worker }
SkSBlockAllocator(GrowthPolicy policy)488*c8dee2aaSAndroid Build Coastguard Worker explicit SkSBlockAllocator(GrowthPolicy policy) {
489*c8dee2aaSAndroid Build Coastguard Worker new (fStorage) SkBlockAllocator(policy, N, N - sizeof(SkBlockAllocator));
490*c8dee2aaSAndroid Build Coastguard Worker }
491*c8dee2aaSAndroid Build Coastguard Worker
SkSBlockAllocator(GrowthPolicy policy,size_t blockIncrementBytes)492*c8dee2aaSAndroid Build Coastguard Worker SkSBlockAllocator(GrowthPolicy policy, size_t blockIncrementBytes) {
493*c8dee2aaSAndroid Build Coastguard Worker new (fStorage) SkBlockAllocator(policy, blockIncrementBytes, N - sizeof(SkBlockAllocator));
494*c8dee2aaSAndroid Build Coastguard Worker }
495*c8dee2aaSAndroid Build Coastguard Worker
~SkSBlockAllocator()496*c8dee2aaSAndroid Build Coastguard Worker ~SkSBlockAllocator() {
497*c8dee2aaSAndroid Build Coastguard Worker this->allocator()->~SkBlockAllocator();
498*c8dee2aaSAndroid Build Coastguard Worker }
499*c8dee2aaSAndroid Build Coastguard Worker
500*c8dee2aaSAndroid Build Coastguard Worker SkBlockAllocator* operator->() { return this->allocator(); }
501*c8dee2aaSAndroid Build Coastguard Worker const SkBlockAllocator* operator->() const { return this->allocator(); }
502*c8dee2aaSAndroid Build Coastguard Worker
allocator()503*c8dee2aaSAndroid Build Coastguard Worker SkBlockAllocator* allocator() { return reinterpret_cast<SkBlockAllocator*>(fStorage); }
allocator()504*c8dee2aaSAndroid Build Coastguard Worker const SkBlockAllocator* allocator() const {
505*c8dee2aaSAndroid Build Coastguard Worker return reinterpret_cast<const SkBlockAllocator*>(fStorage);
506*c8dee2aaSAndroid Build Coastguard Worker }
507*c8dee2aaSAndroid Build Coastguard Worker
508*c8dee2aaSAndroid Build Coastguard Worker private:
509*c8dee2aaSAndroid Build Coastguard Worker static_assert(N >= sizeof(SkBlockAllocator));
510*c8dee2aaSAndroid Build Coastguard Worker
511*c8dee2aaSAndroid Build Coastguard Worker // Will be used to placement new the allocator
512*c8dee2aaSAndroid Build Coastguard Worker alignas(SkBlockAllocator) char fStorage[N];
513*c8dee2aaSAndroid Build Coastguard Worker };
514*c8dee2aaSAndroid Build Coastguard Worker
515*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
516*c8dee2aaSAndroid Build Coastguard Worker // Template and inline implementations
517*c8dee2aaSAndroid Build Coastguard Worker
SK_MAKE_BITFIELD_OPS(SkBlockAllocator::ReserveFlags)518*c8dee2aaSAndroid Build Coastguard Worker SK_MAKE_BITFIELD_OPS(SkBlockAllocator::ReserveFlags)
519*c8dee2aaSAndroid Build Coastguard Worker
520*c8dee2aaSAndroid Build Coastguard Worker template<size_t Align, size_t Padding>
521*c8dee2aaSAndroid Build Coastguard Worker constexpr size_t SkBlockAllocator::BlockOverhead() {
522*c8dee2aaSAndroid Build Coastguard Worker static_assert(SkAlignTo(kDataStart + Padding, Align) >= sizeof(Block));
523*c8dee2aaSAndroid Build Coastguard Worker return SkAlignTo(kDataStart + Padding, Align);
524*c8dee2aaSAndroid Build Coastguard Worker }
525*c8dee2aaSAndroid Build Coastguard Worker
526*c8dee2aaSAndroid Build Coastguard Worker template<size_t Align, size_t Padding>
Overhead()527*c8dee2aaSAndroid Build Coastguard Worker constexpr size_t SkBlockAllocator::Overhead() {
528*c8dee2aaSAndroid Build Coastguard Worker // NOTE: On most platforms, SkBlockAllocator is packed; this is not the case on debug builds
529*c8dee2aaSAndroid Build Coastguard Worker // due to extra fields, or on WASM due to 4byte pointers but 16byte max align.
530*c8dee2aaSAndroid Build Coastguard Worker return std::max(sizeof(SkBlockAllocator),
531*c8dee2aaSAndroid Build Coastguard Worker offsetof(SkBlockAllocator, fHead) + BlockOverhead<Align, Padding>());
532*c8dee2aaSAndroid Build Coastguard Worker }
533*c8dee2aaSAndroid Build Coastguard Worker
534*c8dee2aaSAndroid Build Coastguard Worker template<size_t Align, size_t Padding>
MaxBlockSize()535*c8dee2aaSAndroid Build Coastguard Worker constexpr size_t SkBlockAllocator::MaxBlockSize() {
536*c8dee2aaSAndroid Build Coastguard Worker // Without loss of generality, assumes 'align' will be the largest encountered alignment for the
537*c8dee2aaSAndroid Build Coastguard Worker // allocator (if it's not, the largest align will be encountered by the compiler and pass/fail
538*c8dee2aaSAndroid Build Coastguard Worker // the same set of static asserts).
539*c8dee2aaSAndroid Build Coastguard Worker return BlockOverhead<Align, Padding>() + kMaxAllocationSize;
540*c8dee2aaSAndroid Build Coastguard Worker }
541*c8dee2aaSAndroid Build Coastguard Worker
542*c8dee2aaSAndroid Build Coastguard Worker template<size_t Align, size_t Padding>
reserve(size_t size,ReserveFlags flags)543*c8dee2aaSAndroid Build Coastguard Worker void SkBlockAllocator::reserve(size_t size, ReserveFlags flags) {
544*c8dee2aaSAndroid Build Coastguard Worker if (size > kMaxAllocationSize) {
545*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Allocation too large (%zu bytes requested)", size);
546*c8dee2aaSAndroid Build Coastguard Worker }
547*c8dee2aaSAndroid Build Coastguard Worker int iSize = (int) size;
548*c8dee2aaSAndroid Build Coastguard Worker if ((flags & kIgnoreExistingBytes_Flag) ||
549*c8dee2aaSAndroid Build Coastguard Worker this->currentBlock()->avail<Align, Padding>() < iSize) {
550*c8dee2aaSAndroid Build Coastguard Worker
551*c8dee2aaSAndroid Build Coastguard Worker int blockSize = BlockOverhead<Align, Padding>() + iSize;
552*c8dee2aaSAndroid Build Coastguard Worker int maxSize = (flags & kIgnoreGrowthPolicy_Flag) ? blockSize
553*c8dee2aaSAndroid Build Coastguard Worker : MaxBlockSize<Align, Padding>();
554*c8dee2aaSAndroid Build Coastguard Worker SkASSERT((size_t) maxSize <= (MaxBlockSize<Align, Padding>()));
555*c8dee2aaSAndroid Build Coastguard Worker
556*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(auto oldTail = fTail;)
557*c8dee2aaSAndroid Build Coastguard Worker this->addBlock(blockSize, maxSize);
558*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fTail != oldTail);
559*c8dee2aaSAndroid Build Coastguard Worker // Releasing the just added block will move it into scratch space, allowing the original
560*c8dee2aaSAndroid Build Coastguard Worker // tail's bytes to be used first before the scratch block is activated.
561*c8dee2aaSAndroid Build Coastguard Worker this->releaseBlock(fTail);
562*c8dee2aaSAndroid Build Coastguard Worker }
563*c8dee2aaSAndroid Build Coastguard Worker }
564*c8dee2aaSAndroid Build Coastguard Worker
565*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align, size_t Padding>
allocate(size_t size)566*c8dee2aaSAndroid Build Coastguard Worker SkBlockAllocator::ByteRange SkBlockAllocator::allocate(size_t size) {
567*c8dee2aaSAndroid Build Coastguard Worker // Amount of extra space for a new block to make sure the allocation can succeed.
568*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kBlockOverhead = (int) BlockOverhead<Align, Padding>();
569*c8dee2aaSAndroid Build Coastguard Worker
570*c8dee2aaSAndroid Build Coastguard Worker // Ensures 'offset' and 'end' calculations will be valid
571*c8dee2aaSAndroid Build Coastguard Worker static_assert((kMaxAllocationSize + SkAlignTo(MaxBlockSize<Align, Padding>(), Align))
572*c8dee2aaSAndroid Build Coastguard Worker <= (size_t) std::numeric_limits<int32_t>::max());
573*c8dee2aaSAndroid Build Coastguard Worker // Ensures size + blockOverhead + addBlock's alignment operations will be valid
574*c8dee2aaSAndroid Build Coastguard Worker static_assert(kMaxAllocationSize + kBlockOverhead + ((1 << 12) - 1) // 4K align for large blocks
575*c8dee2aaSAndroid Build Coastguard Worker <= std::numeric_limits<int32_t>::max());
576*c8dee2aaSAndroid Build Coastguard Worker
577*c8dee2aaSAndroid Build Coastguard Worker if (size > kMaxAllocationSize) {
578*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Allocation too large (%zu bytes requested)", size);
579*c8dee2aaSAndroid Build Coastguard Worker }
580*c8dee2aaSAndroid Build Coastguard Worker
581*c8dee2aaSAndroid Build Coastguard Worker int iSize = (int) size;
582*c8dee2aaSAndroid Build Coastguard Worker int offset = fTail->cursor<Align, Padding>();
583*c8dee2aaSAndroid Build Coastguard Worker int end = offset + iSize;
584*c8dee2aaSAndroid Build Coastguard Worker if (end > fTail->fSize) {
585*c8dee2aaSAndroid Build Coastguard Worker this->addBlock(iSize + kBlockOverhead, MaxBlockSize<Align, Padding>());
586*c8dee2aaSAndroid Build Coastguard Worker offset = fTail->cursor<Align, Padding>();
587*c8dee2aaSAndroid Build Coastguard Worker end = offset + iSize;
588*c8dee2aaSAndroid Build Coastguard Worker }
589*c8dee2aaSAndroid Build Coastguard Worker
590*c8dee2aaSAndroid Build Coastguard Worker // Check invariants
591*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(end <= fTail->fSize);
592*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(end - offset == iSize);
593*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(offset - fTail->fCursor >= (int) Padding &&
594*c8dee2aaSAndroid Build Coastguard Worker offset - fTail->fCursor <= (int) (Padding + Align - 1));
595*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(reinterpret_cast<uintptr_t>(fTail->ptr(offset)) % Align == 0);
596*c8dee2aaSAndroid Build Coastguard Worker
597*c8dee2aaSAndroid Build Coastguard Worker int start = fTail->fCursor;
598*c8dee2aaSAndroid Build Coastguard Worker fTail->fCursor = end;
599*c8dee2aaSAndroid Build Coastguard Worker
600*c8dee2aaSAndroid Build Coastguard Worker fTail->unpoisonRange(offset - Padding, end);
601*c8dee2aaSAndroid Build Coastguard Worker
602*c8dee2aaSAndroid Build Coastguard Worker return {fTail, start, offset, end};
603*c8dee2aaSAndroid Build Coastguard Worker }
604*c8dee2aaSAndroid Build Coastguard Worker
605*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align, size_t Padding>
owningBlock(const void * p,int start)606*c8dee2aaSAndroid Build Coastguard Worker SkBlockAllocator::Block* SkBlockAllocator::owningBlock(const void* p, int start) {
607*c8dee2aaSAndroid Build Coastguard Worker // 'p' was originally formed by aligning 'block + start + Padding', producing the inequality:
608*c8dee2aaSAndroid Build Coastguard Worker // block + start + Padding <= p <= block + start + Padding + Align-1
609*c8dee2aaSAndroid Build Coastguard Worker // Rearranging this yields:
610*c8dee2aaSAndroid Build Coastguard Worker // block <= p - start - Padding <= block + Align-1
611*c8dee2aaSAndroid Build Coastguard Worker // Masking these terms by ~(Align-1) reconstructs 'block' if the alignment of the block is
612*c8dee2aaSAndroid Build Coastguard Worker // greater than or equal to Align (since block & ~(Align-1) == (block + Align-1) & ~(Align-1)
613*c8dee2aaSAndroid Build Coastguard Worker // in that case). Overalignment does not reduce to inequality unfortunately.
614*c8dee2aaSAndroid Build Coastguard Worker if /* constexpr */ (Align <= kAddressAlign) {
615*c8dee2aaSAndroid Build Coastguard Worker Block* block = reinterpret_cast<Block*>(
616*c8dee2aaSAndroid Build Coastguard Worker (reinterpret_cast<uintptr_t>(p) - start - Padding) & ~(Align - 1));
617*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(block->fSentinel == kAssignedMarker);
618*c8dee2aaSAndroid Build Coastguard Worker return block;
619*c8dee2aaSAndroid Build Coastguard Worker } else {
620*c8dee2aaSAndroid Build Coastguard Worker // There's not a constant-time expression available to reconstruct the block from 'p',
621*c8dee2aaSAndroid Build Coastguard Worker // but this is unlikely to happen frequently.
622*c8dee2aaSAndroid Build Coastguard Worker return this->findOwningBlock(p);
623*c8dee2aaSAndroid Build Coastguard Worker }
624*c8dee2aaSAndroid Build Coastguard Worker }
625*c8dee2aaSAndroid Build Coastguard Worker
626*c8dee2aaSAndroid Build Coastguard Worker template <size_t Align, size_t Padding>
alignedOffset(int offset)627*c8dee2aaSAndroid Build Coastguard Worker int SkBlockAllocator::Block::alignedOffset(int offset) const {
628*c8dee2aaSAndroid Build Coastguard Worker static_assert(SkIsPow2(Align));
629*c8dee2aaSAndroid Build Coastguard Worker // Aligning adds (Padding + Align - 1) as an intermediate step, so ensure that can't overflow
630*c8dee2aaSAndroid Build Coastguard Worker static_assert(MaxBlockSize<Align, Padding>() + Padding + Align - 1
631*c8dee2aaSAndroid Build Coastguard Worker <= (size_t) std::numeric_limits<int32_t>::max());
632*c8dee2aaSAndroid Build Coastguard Worker
633*c8dee2aaSAndroid Build Coastguard Worker if /* constexpr */ (Align <= kAddressAlign) {
634*c8dee2aaSAndroid Build Coastguard Worker // Same as SkAlignTo, but operates on ints instead of size_t
635*c8dee2aaSAndroid Build Coastguard Worker return (offset + Padding + Align - 1) & ~(Align - 1);
636*c8dee2aaSAndroid Build Coastguard Worker } else {
637*c8dee2aaSAndroid Build Coastguard Worker // Must take into account that 'this' may be starting at a pointer that doesn't satisfy the
638*c8dee2aaSAndroid Build Coastguard Worker // larger alignment request, so must align the entire pointer, not just offset
639*c8dee2aaSAndroid Build Coastguard Worker uintptr_t blockPtr = reinterpret_cast<uintptr_t>(this);
640*c8dee2aaSAndroid Build Coastguard Worker uintptr_t alignedPtr = (blockPtr + offset + Padding + Align - 1) & ~(Align - 1);
641*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(alignedPtr - blockPtr <= (uintptr_t) std::numeric_limits<int32_t>::max());
642*c8dee2aaSAndroid Build Coastguard Worker return (int) (alignedPtr - blockPtr);
643*c8dee2aaSAndroid Build Coastguard Worker }
644*c8dee2aaSAndroid Build Coastguard Worker }
645*c8dee2aaSAndroid Build Coastguard Worker
resize(int start,int end,int deltaBytes)646*c8dee2aaSAndroid Build Coastguard Worker bool SkBlockAllocator::Block::resize(int start, int end, int deltaBytes) {
647*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fSentinel == kAssignedMarker);
648*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(start >= kDataStart && end <= fSize && start < end);
649*c8dee2aaSAndroid Build Coastguard Worker
650*c8dee2aaSAndroid Build Coastguard Worker if (deltaBytes > kMaxAllocationSize || deltaBytes < -kMaxAllocationSize) {
651*c8dee2aaSAndroid Build Coastguard Worker // Cannot possibly satisfy the resize and could overflow subsequent math
652*c8dee2aaSAndroid Build Coastguard Worker return false;
653*c8dee2aaSAndroid Build Coastguard Worker }
654*c8dee2aaSAndroid Build Coastguard Worker if (fCursor == end) {
655*c8dee2aaSAndroid Build Coastguard Worker int nextCursor = end + deltaBytes;
656*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(nextCursor >= start);
657*c8dee2aaSAndroid Build Coastguard Worker // We still check nextCursor >= start for release builds that wouldn't assert.
658*c8dee2aaSAndroid Build Coastguard Worker if (nextCursor <= fSize && nextCursor >= start) {
659*c8dee2aaSAndroid Build Coastguard Worker if (nextCursor < fCursor) {
660*c8dee2aaSAndroid Build Coastguard Worker // The allocation got smaller; poison the space that can no longer be used.
661*c8dee2aaSAndroid Build Coastguard Worker this->poisonRange(nextCursor + 1, end);
662*c8dee2aaSAndroid Build Coastguard Worker } else {
663*c8dee2aaSAndroid Build Coastguard Worker // The allocation got larger; unpoison the space that can now be used.
664*c8dee2aaSAndroid Build Coastguard Worker this->unpoisonRange(end, nextCursor);
665*c8dee2aaSAndroid Build Coastguard Worker }
666*c8dee2aaSAndroid Build Coastguard Worker
667*c8dee2aaSAndroid Build Coastguard Worker fCursor = nextCursor;
668*c8dee2aaSAndroid Build Coastguard Worker return true;
669*c8dee2aaSAndroid Build Coastguard Worker }
670*c8dee2aaSAndroid Build Coastguard Worker }
671*c8dee2aaSAndroid Build Coastguard Worker return false;
672*c8dee2aaSAndroid Build Coastguard Worker }
673*c8dee2aaSAndroid Build Coastguard Worker
674*c8dee2aaSAndroid Build Coastguard Worker // NOTE: release is equivalent to resize(start, end, start - end), and the compiler can optimize
675*c8dee2aaSAndroid Build Coastguard Worker // most of the operations away, but it wasn't able to remove the unnecessary branch comparing the
676*c8dee2aaSAndroid Build Coastguard Worker // new cursor to the block size or old start, so release() gets a specialization.
release(int start,int end)677*c8dee2aaSAndroid Build Coastguard Worker bool SkBlockAllocator::Block::release(int start, int end) {
678*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fSentinel == kAssignedMarker);
679*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(start >= kDataStart && end <= fSize && start < end);
680*c8dee2aaSAndroid Build Coastguard Worker
681*c8dee2aaSAndroid Build Coastguard Worker this->poisonRange(start, end);
682*c8dee2aaSAndroid Build Coastguard Worker
683*c8dee2aaSAndroid Build Coastguard Worker if (fCursor == end) {
684*c8dee2aaSAndroid Build Coastguard Worker fCursor = start;
685*c8dee2aaSAndroid Build Coastguard Worker return true;
686*c8dee2aaSAndroid Build Coastguard Worker } else {
687*c8dee2aaSAndroid Build Coastguard Worker return false;
688*c8dee2aaSAndroid Build Coastguard Worker }
689*c8dee2aaSAndroid Build Coastguard Worker }
690*c8dee2aaSAndroid Build Coastguard Worker
691*c8dee2aaSAndroid Build Coastguard Worker ///////// Block iteration
692*c8dee2aaSAndroid Build Coastguard Worker template <bool Forward, bool Const>
693*c8dee2aaSAndroid Build Coastguard Worker class SkBlockAllocator::BlockIter {
694*c8dee2aaSAndroid Build Coastguard Worker private:
695*c8dee2aaSAndroid Build Coastguard Worker using BlockT = typename std::conditional<Const, const Block, Block>::type;
696*c8dee2aaSAndroid Build Coastguard Worker using AllocatorT =
697*c8dee2aaSAndroid Build Coastguard Worker typename std::conditional<Const, const SkBlockAllocator, SkBlockAllocator>::type;
698*c8dee2aaSAndroid Build Coastguard Worker
699*c8dee2aaSAndroid Build Coastguard Worker public:
BlockIter(AllocatorT * allocator)700*c8dee2aaSAndroid Build Coastguard Worker BlockIter(AllocatorT* allocator) : fAllocator(allocator) {}
701*c8dee2aaSAndroid Build Coastguard Worker
702*c8dee2aaSAndroid Build Coastguard Worker class Item {
703*c8dee2aaSAndroid Build Coastguard Worker public:
704*c8dee2aaSAndroid Build Coastguard Worker bool operator!=(const Item& other) const { return fBlock != other.fBlock; }
705*c8dee2aaSAndroid Build Coastguard Worker
706*c8dee2aaSAndroid Build Coastguard Worker BlockT* operator*() const { return fBlock; }
707*c8dee2aaSAndroid Build Coastguard Worker
708*c8dee2aaSAndroid Build Coastguard Worker Item& operator++() {
709*c8dee2aaSAndroid Build Coastguard Worker this->advance(fNext);
710*c8dee2aaSAndroid Build Coastguard Worker return *this;
711*c8dee2aaSAndroid Build Coastguard Worker }
712*c8dee2aaSAndroid Build Coastguard Worker
713*c8dee2aaSAndroid Build Coastguard Worker private:
714*c8dee2aaSAndroid Build Coastguard Worker friend BlockIter;
715*c8dee2aaSAndroid Build Coastguard Worker
Item(BlockT * block)716*c8dee2aaSAndroid Build Coastguard Worker Item(BlockT* block) { this->advance(block); }
717*c8dee2aaSAndroid Build Coastguard Worker
advance(BlockT * block)718*c8dee2aaSAndroid Build Coastguard Worker void advance(BlockT* block) {
719*c8dee2aaSAndroid Build Coastguard Worker fBlock = block;
720*c8dee2aaSAndroid Build Coastguard Worker fNext = block ? (Forward ? block->fNext : block->fPrev) : nullptr;
721*c8dee2aaSAndroid Build Coastguard Worker if (!Forward && fNext && fNext->isScratch()) {
722*c8dee2aaSAndroid Build Coastguard Worker // For reverse-iteration only, we need to stop at the head, not the scratch block
723*c8dee2aaSAndroid Build Coastguard Worker // possibly stashed in head->prev.
724*c8dee2aaSAndroid Build Coastguard Worker fNext = nullptr;
725*c8dee2aaSAndroid Build Coastguard Worker }
726*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fNext || !fNext->isScratch());
727*c8dee2aaSAndroid Build Coastguard Worker }
728*c8dee2aaSAndroid Build Coastguard Worker
729*c8dee2aaSAndroid Build Coastguard Worker BlockT* fBlock;
730*c8dee2aaSAndroid Build Coastguard Worker // Cache this before operator++ so that fBlock can be released during iteration
731*c8dee2aaSAndroid Build Coastguard Worker BlockT* fNext;
732*c8dee2aaSAndroid Build Coastguard Worker };
733*c8dee2aaSAndroid Build Coastguard Worker
begin()734*c8dee2aaSAndroid Build Coastguard Worker Item begin() const { return Item(Forward ? &fAllocator->fHead : fAllocator->fTail); }
end()735*c8dee2aaSAndroid Build Coastguard Worker Item end() const { return Item(nullptr); }
736*c8dee2aaSAndroid Build Coastguard Worker
737*c8dee2aaSAndroid Build Coastguard Worker private:
738*c8dee2aaSAndroid Build Coastguard Worker AllocatorT* fAllocator;
739*c8dee2aaSAndroid Build Coastguard Worker };
740*c8dee2aaSAndroid Build Coastguard Worker
blocks()741*c8dee2aaSAndroid Build Coastguard Worker SkBlockAllocator::BlockIter<true, false> SkBlockAllocator::blocks() {
742*c8dee2aaSAndroid Build Coastguard Worker return BlockIter<true, false>(this);
743*c8dee2aaSAndroid Build Coastguard Worker }
blocks()744*c8dee2aaSAndroid Build Coastguard Worker SkBlockAllocator::BlockIter<true, true> SkBlockAllocator::blocks() const {
745*c8dee2aaSAndroid Build Coastguard Worker return BlockIter<true, true>(this);
746*c8dee2aaSAndroid Build Coastguard Worker }
rblocks()747*c8dee2aaSAndroid Build Coastguard Worker SkBlockAllocator::BlockIter<false, false> SkBlockAllocator::rblocks() {
748*c8dee2aaSAndroid Build Coastguard Worker return BlockIter<false, false>(this);
749*c8dee2aaSAndroid Build Coastguard Worker }
rblocks()750*c8dee2aaSAndroid Build Coastguard Worker SkBlockAllocator::BlockIter<false, true> SkBlockAllocator::rblocks() const {
751*c8dee2aaSAndroid Build Coastguard Worker return BlockIter<false, true>(this);
752*c8dee2aaSAndroid Build Coastguard Worker }
753*c8dee2aaSAndroid Build Coastguard Worker
754*c8dee2aaSAndroid Build Coastguard Worker #endif // SkBlockAllocator_DEFINED
755