OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkChunkAlloc.h" | 8 #include "SkChunkAlloc.h" |
9 | 9 |
10 // Don't malloc any chunks smaller than this | 10 // Don't malloc any chunks smaller than this |
11 #define MIN_CHUNKALLOC_BLOCK_SIZE 1024 | 11 #define MIN_CHUNKALLOC_BLOCK_SIZE 1024 |
12 | 12 |
13 // Return the new min blocksize given the current value | 13 // Return the new min blocksize given the current value |
14 static size_t increase_next_size(size_t size) { | 14 static size_t increase_next_size(size_t size) { |
15 return size + (size >> 1); | 15 return size + (size >> 1); |
16 } | 16 } |
17 | 17 |
18 /////////////////////////////////////////////////////////////////////////////// | 18 /////////////////////////////////////////////////////////////////////////////// |
19 | 19 |
20 struct SkChunkAlloc::Block { | 20 struct SkChunkAlloc::Block { |
21 Block* fNext; | 21 Block* fNext; |
22 size_t fFreeSize; | 22 size_t fFreeSize; |
23 char* fFreePtr; | 23 char* fFreePtr; |
24 // data[] follows | 24 // data[] follows |
25 | 25 |
| 26 size_t blockSize() { |
| 27 char* start = this->startOfData(); |
| 28 size_t bytes = fFreePtr - start; |
| 29 return fFreeSize + bytes; |
| 30 } |
| 31 |
| 32 void reset() { |
| 33 fNext = NULL; |
| 34 fFreeSize = this->blockSize(); |
| 35 fFreePtr = this->startOfData(); |
| 36 } |
| 37 |
26 char* startOfData() { | 38 char* startOfData() { |
27 return reinterpret_cast<char*>(this + 1); | 39 return reinterpret_cast<char*>(this + 1); |
28 } | 40 } |
29 | 41 |
30 static void FreeChain(Block* block) { | 42 static void FreeChain(Block* block) { |
31 while (block) { | 43 while (block) { |
32 Block* next = block->fNext; | 44 Block* next = block->fNext; |
33 sk_free(block); | 45 sk_free(block); |
34 block = next; | 46 block = next; |
35 } | 47 } |
(...skipping 26 matching lines...) Expand all Loading... |
62 | 74 |
63 void SkChunkAlloc::reset() { | 75 void SkChunkAlloc::reset() { |
64 Block::FreeChain(fBlock); | 76 Block::FreeChain(fBlock); |
65 fBlock = NULL; | 77 fBlock = NULL; |
66 fChunkSize = fMinSize; // reset to our initial minSize | 78 fChunkSize = fMinSize; // reset to our initial minSize |
67 fTotalCapacity = 0; | 79 fTotalCapacity = 0; |
68 fTotalUsed = 0; | 80 fTotalUsed = 0; |
69 fBlockCount = 0; | 81 fBlockCount = 0; |
70 } | 82 } |
71 | 83 |
| 84 void SkChunkAlloc::rewind() { |
| 85 Block* largest = fBlock; |
| 86 |
| 87 if (largest) { |
| 88 Block* next; |
| 89 for (Block* cur = largest->fNext; cur; cur = next) { |
| 90 next = cur->fNext; |
| 91 if (cur->blockSize() > largest->blockSize()) { |
| 92 sk_free(largest); |
| 93 largest = cur; |
| 94 } else { |
| 95 sk_free(cur); |
| 96 } |
| 97 } |
| 98 |
| 99 largest->reset(); |
| 100 fTotalCapacity = largest->blockSize(); |
| 101 fBlockCount = 1; |
| 102 } else { |
| 103 fTotalCapacity = 0; |
| 104 fBlockCount = 0; |
| 105 } |
| 106 |
| 107 fBlock = largest; |
| 108 fChunkSize = fMinSize; // reset to our initial minSize |
| 109 fTotalUsed = 0; |
| 110 } |
| 111 |
72 SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) { | 112 SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) { |
73 size_t size = bytes; | 113 size_t size = bytes; |
74 if (size < fChunkSize) { | 114 if (size < fChunkSize) { |
75 size = fChunkSize; | 115 size = fChunkSize; |
76 } | 116 } |
77 | 117 |
78 Block* block = (Block*)sk_malloc_flags(sizeof(Block) + size, | 118 Block* block = (Block*)sk_malloc_flags(sizeof(Block) + size, |
79 ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0); | 119 ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0); |
80 | 120 |
81 if (block) { | 121 if (block) { |
82 // block->fNext = fBlock; | |
83 block->fFreeSize = size; | 122 block->fFreeSize = size; |
84 block->fFreePtr = block->startOfData(); | 123 block->fFreePtr = block->startOfData(); |
85 | 124 |
86 fTotalCapacity += size; | 125 fTotalCapacity += size; |
87 fBlockCount += 1; | 126 fBlockCount += 1; |
88 | 127 |
89 fChunkSize = increase_next_size(fChunkSize); | 128 fChunkSize = increase_next_size(fChunkSize); |
90 } | 129 } |
91 return block; | 130 return block; |
92 } | 131 } |
93 | 132 |
| 133 SkChunkAlloc::Block* SkChunkAlloc::addBlockIfNecessary(size_t bytes, AllocFailTy
pe ftype) { |
| 134 SkASSERT(SkIsAlign4(bytes)); |
| 135 |
| 136 if (!fBlock || bytes > fBlock->fFreeSize) { |
| 137 Block* block = this->newBlock(bytes, ftype); |
| 138 if (!block) { |
| 139 return NULL; |
| 140 } |
| 141 block->fNext = fBlock; |
| 142 fBlock = block; |
| 143 } |
| 144 |
| 145 SkASSERT(fBlock && bytes <= fBlock->fFreeSize); |
| 146 return fBlock; |
| 147 } |
| 148 |
| 149 void SkChunkAlloc::preAlloc(size_t bytes) { |
| 150 bytes = SkAlign4(bytes); |
| 151 |
| 152 this->addBlockIfNecessary(bytes, kReturnNil_AllocFailType); |
| 153 } |
| 154 |
94 void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) { | 155 void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) { |
95 fTotalUsed += bytes; | 156 fTotalUsed += bytes; |
96 | 157 |
97 bytes = SkAlign4(bytes); | 158 bytes = SkAlign4(bytes); |
98 | 159 |
99 Block* block = fBlock; | 160 Block* block = this->addBlockIfNecessary(bytes, ftype); |
100 | 161 if (!block) { |
101 if (block == NULL || bytes > block->fFreeSize) { | 162 return NULL; |
102 block = this->newBlock(bytes, ftype); | |
103 if (NULL == block) { | |
104 return NULL; | |
105 } | |
106 block->fNext = fBlock; | |
107 fBlock = block; | |
108 } | 163 } |
109 | 164 |
110 SkASSERT(block && bytes <= block->fFreeSize); | |
111 char* ptr = block->fFreePtr; | 165 char* ptr = block->fFreePtr; |
112 | 166 |
113 block->fFreeSize -= bytes; | 167 block->fFreeSize -= bytes; |
114 block->fFreePtr = ptr + bytes; | 168 block->fFreePtr = ptr + bytes; |
115 return ptr; | 169 return ptr; |
116 } | 170 } |
117 | 171 |
118 size_t SkChunkAlloc::unalloc(void* ptr) { | 172 size_t SkChunkAlloc::unalloc(void* ptr) { |
119 size_t bytes = 0; | 173 size_t bytes = 0; |
120 Block* block = fBlock; | 174 Block* block = fBlock; |
121 if (block) { | 175 if (block) { |
122 char* cPtr = reinterpret_cast<char*>(ptr); | 176 char* cPtr = reinterpret_cast<char*>(ptr); |
123 char* start = block->startOfData(); | 177 char* start = block->startOfData(); |
124 if (start <= cPtr && cPtr < block->fFreePtr) { | 178 if (start <= cPtr && cPtr < block->fFreePtr) { |
125 bytes = block->fFreePtr - cPtr; | 179 bytes = block->fFreePtr - cPtr; |
| 180 fTotalUsed -= bytes; |
126 block->fFreeSize += bytes; | 181 block->fFreeSize += bytes; |
127 block->fFreePtr = cPtr; | 182 block->fFreePtr = cPtr; |
128 } | 183 } |
129 } | 184 } |
130 return bytes; | 185 return bytes; |
131 } | 186 } |
132 | 187 |
133 bool SkChunkAlloc::contains(const void* addr) const { | 188 bool SkChunkAlloc::contains(const void* addr) const { |
134 const Block* block = fBlock; | 189 const Block* block = fBlock; |
135 while (block) { | 190 while (block) { |
136 if (block->contains(addr)) { | 191 if (block->contains(addr)) { |
137 return true; | 192 return true; |
138 } | 193 } |
139 block = block->fNext; | 194 block = block->fNext; |
140 } | 195 } |
141 return false; | 196 return false; |
142 } | 197 } |
OLD | NEW |