1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | #include "MMgc.h" |
42 | |
43 | namespace MMgc |
44 | { |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | #ifdef MMGC_64BIT |
74 | const int16_t FixedMalloc::kSizeClasses[kNumSizeClasses] = { |
75 | 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, |
76 | 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, |
77 | 168, 176, 192, 208, 224, 232, 248, 264, 288, 304, |
78 | 336, 360, 400, 448, 504, 576, 672, 800, 1008, 1344, |
79 | 2016, |
80 | }; |
81 | |
82 | const uint8_t FixedMalloc::kSizeClassIndex[kMaxSizeClassIndex] = { |
83 | 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
84 | 15, 16, 17, 18, 19, 20, 21, 22, 22, 23, 23, 24, 24, 25, 26, 26, |
85 | 27, 27, 28, 28, 28, 29, 29, 30, 30, 30, 30, 31, 31, 31, 32, 32, |
86 | 32, 32, 32, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, |
87 | 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, |
88 | 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, |
89 | 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, |
90 | 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, |
91 | 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, |
92 | 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, |
93 | 39, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, |
94 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, |
95 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, |
96 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, |
97 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, |
98 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40 |
99 | }; |
100 | |
101 | #else |
102 | const int16_t FixedMalloc::kSizeClasses[kNumSizeClasses] = { |
103 | 4, 8, 16, 24, 32, 40, 48, 56, 64, 72, |
104 | 80, 88, 96, 104, 112, 120, 128, 144, 160, 176, |
105 | 184, 192, 200, 208, 224, 232, 248, 264, 288, 312, |
106 | 336, 368, 400, 448, 504, 576, 672, 808, 1016, 1352, |
107 | 2032, |
108 | }; |
109 | |
110 | const uint8_t FixedMalloc::kSizeClassIndex[kMaxSizeClassIndex] = { |
111 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, |
112 | 16, 17, 17, 18, 18, 19, 19, 20, 21, 22, 23, 24, 24, 25, 26, 26, |
113 | 27, 27, 28, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 31, 32, |
114 | 32, 32, 32, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, |
115 | 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, |
116 | 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, |
117 | 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, |
118 | 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, |
119 | 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, |
120 | 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, |
121 | 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, |
122 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, |
123 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, |
124 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, |
125 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, |
126 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40 |
127 | }; |
128 | |
129 | #endif |
130 | |
131 | #if defined DEBUG |
132 | |
133 | |
134 | |
135 | |
136 | struct FixedMalloc::LargeObject |
137 | { |
138 | const void *item; |
139 | LargeObject* next; |
140 | }; |
141 | #endif |
142 | |
143 | |
144 | FixedMalloc *FixedMalloc::instance; |
145 | |
146 | void FixedMalloc::InitInstance(GCHeap* heap) |
147 | { |
148 | |
149 | |
150 | GCAssert(GCHeap::kBlockSize == 4096)do { } while (0); |
151 | |
152 | m_heap = heap; |
153 | numLargeBlocks = 0; |
154 | VMPI_lockInit(&m_largeAllocInfoLock); |
155 | #ifdef MMGC_MEMORY_PROFILER |
156 | totalAskSizeLargeAllocs = 0; |
157 | #endif |
158 | #if defined DEBUG && !defined AVMPLUS_SAMPLER |
159 | largeObjects = NULL__null; |
160 | VMPI_lockInit(&m_largeObjectLock); |
161 | #endif |
162 | |
163 | for (int i=0; i<kNumSizeClasses; i++) |
164 | m_allocs[i].Init((uint32_t)kSizeClasses[i], heap); |
165 | |
166 | FixedMalloc::instance = this; |
167 | } |
168 | |
169 | void FixedMalloc::DestroyInstance() |
170 | { |
171 | for (int i=0; i<kNumSizeClasses; i++) |
172 | m_allocs[i].Destroy(); |
173 | |
174 | VMPI_lockDestroy(&m_largeAllocInfoLock); |
175 | #if defined DEBUG && !defined AVMPLUS_SAMPLER |
176 | VMPI_lockDestroy(&m_largeObjectLock); |
177 | #endif |
178 | |
179 | FixedMalloc::instance = NULL__null; |
180 | } |
181 | |
182 | void* FASTCALL__attribute__((fastcall)) FixedMalloc::OutOfLineAlloc(size_t size, FixedMallocOpts flags) |
183 | { |
184 | return Alloc(size, flags); |
185 | } |
186 | |
187 | void FASTCALL__attribute__((fastcall)) FixedMalloc::OutOfLineFree(void* p) |
188 | { |
189 | Free(p); |
190 | } |
191 | |
192 | void FixedMalloc::GetUsageInfo(size_t& totalAskSize, size_t& totalAllocated) |
193 | { |
194 | totalAskSize = 0; |
195 | totalAllocated = 0; |
196 | for (int i=0; i<kNumSizeClasses; i++) { |
197 | size_t allocated = 0; |
198 | size_t ask = 0; |
199 | m_allocs[i].GetUsageInfo(ask, allocated); |
200 | totalAskSize += ask; |
201 | totalAllocated += allocated; |
202 | } |
203 | |
204 | #ifdef MMGC_MEMORY_PROFILER |
205 | { |
206 | MMGC_LOCK(m_largeAllocInfoLock)MMgc::GCAcquireSpinlock _lock(&m_largeAllocInfoLock); |
207 | totalAskSize += totalAskSizeLargeAllocs; |
208 | } |
209 | #endif |
210 | |
211 | |
212 | |
213 | totalAllocated += (GetNumLargeBlocks() * GCHeap::kBlockSize); |
214 | } |
215 | |
216 | void *FixedMalloc::LargeAlloc(size_t size, FixedMallocOpts flags) |
217 | { |
218 | GCHeap::CheckForAllocSizeOverflow(size, GCHeap::kBlockSize+DebugSize()0); |
219 | |
220 | size += DebugSize()0; |
221 | |
222 | int blocksNeeded = (int)GCHeap::SizeToBlocks(size); |
223 | uint32_t gcheap_flags = GCHeap::kExpand; |
224 | |
225 | if((flags & kCanFail) != 0) |
| |
226 | gcheap_flags |= GCHeap::kCanFail; |
227 | if((flags & kZero) != 0) |
| |
228 | gcheap_flags |= GCHeap::kZero; |
229 | |
230 | void *item = m_heap->Alloc(blocksNeeded, gcheap_flags); |
231 | if(item) |
| |
232 | { |
233 | VALGRIND_CREATE_MEMPOOL(item, 0, (flags & kZero) != 0){}; |
234 | |
235 | item = GetUserPointer(item)item; |
| 4 | Assigned value is always the same as the existing value |
|
236 | #ifdef MMGC_HOOKS |
237 | if(m_heap->HooksEnabled()) |
238 | m_heap->AllocHook(item, size - DebugSize()0, Size(item), falsefalse); |
239 | #endif // MMGC_HOOKS |
240 | |
241 | UpdateLargeAllocStats(item, blocksNeeded); |
242 | |
243 | #ifdef DEBUG |
244 | |
245 | if ((flags & kZero) == 0 && !RUNNING_ON_VALGRINDfalse) |
246 | memset(item, uint8_t(GCHeap::FXFreshPoison), size - DebugSize()0); |
247 | |
248 | #ifndef AVMPLUS_SAMPLER |
249 | |
250 | AddToLargeObjectTracker(item); |
251 | #endif |
252 | #endif // DEBUG |
253 | |
254 | VALGRIND_MEMPOOL_ALLOC(GetRealPointer(item), item, Size(item)){}; |
255 | } |
256 | return item; |
257 | } |
258 | |
259 | void FixedMalloc::LargeFree(void *item) |
260 | { |
261 | #if defined DEBUG && !defined AVMPLUS_SAMPLER |
262 | RemoveFromLargeObjectTracker(item); |
263 | #endif |
264 | UpdateLargeFreeStats(item, GCHeap::SizeToBlocks(LargeSize(item))); |
265 | |
266 | #ifdef MMGC_HOOKS |
267 | if(m_heap->HooksEnabled()) |
268 | { |
269 | m_heap->FinalizeHook(item, Size(item)); |
270 | m_heap->FreeHook(item, Size(item), uint8_t(GCHeap::FXFreedPoison)); |
271 | } |
272 | #endif |
273 | m_heap->FreeNoProfile(GetRealPointer(item)item); |
274 | VALGRIND_MEMPOOL_FREE(GetRealPointer(item), item){}; |
275 | VALGRIND_DESTROY_MEMPOOL(GetRealPointer(item)){}; |
276 | } |
277 | |
278 | size_t FixedMalloc::LargeSize(const void *item) |
279 | { |
280 | return m_heap->Size(GetRealPointer(item)item) * GCHeap::kBlockSize; |
281 | } |
282 | |
283 | void *FixedMalloc::Calloc(size_t count, size_t elsize, FixedMallocOpts opts) |
284 | { |
285 | return Alloc(GCHeap::CheckForCallocSizeOverflow(count, elsize), opts); |
286 | } |
287 | |
288 | size_t FixedMalloc::GetTotalSize() |
289 | { |
290 | size_t total = GetNumLargeBlocks(); |
291 | for (int i=0; i<kNumSizeClasses; i++) |
292 | total += m_allocs[i].GetNumBlocks(); |
293 | return total; |
294 | } |
295 | |
296 | #ifdef MMGC_MEMORY_PROFILER |
297 | void FixedMalloc::DumpMemoryInfo() |
298 | { |
299 | size_t inUse, ask; |
300 | GetUsageInfo(ask, inUse); |
301 | GCLog("[mem] FixedMalloc total %d pages inuse %d bytes ask %d bytes\n", GetTotalSize(), inUse, ask); |
302 | for (int i=0; i<kNumSizeClasses; i++) { |
303 | m_allocs[i].GetUsageInfo(ask, inUse); |
304 | if( m_allocs[i].GetNumBlocks() > 0) |
305 | GCLog("[mem] FixedMalloc[%d] total %d pages inuse %d bytes ask %d bytes\n", kSizeClasses[i], m_allocs[i].GetNumBlocks(), inUse, ask); |
306 | } |
307 | GCLog("[mem] FixedMalloc[large] total %d pages\n", GetNumLargeBlocks()); |
308 | } |
309 | #endif |
310 | |
311 | #ifdef DEBUG |
312 | |
313 | |
314 | |
315 | |
316 | |
317 | |
318 | |
319 | void FixedMalloc::EnsureFixedMallocMemory(const void* item) |
320 | { |
321 | |
322 | if (!m_heap->config.checkFixedMemory()) |
323 | return; |
324 | |
325 | for (int i=0; i<kNumSizeClasses; i++) |
326 | if (m_allocs[i].QueryOwnsObject(item)) |
327 | return; |
328 | |
329 | #ifdef AVMPLUS_SAMPLER |
330 | if (m_heap->SafeSize(GetRealPointer(item)item) != (size_t)-1) |
331 | return; |
332 | #else |
333 | { |
334 | MMGC_LOCK(m_largeObjectLock)MMgc::GCAcquireSpinlock _lock(&m_largeObjectLock); |
335 | for ( LargeObject* lo=largeObjects; lo != NULL__null ; lo=lo->next) |
336 | if (lo->item == item) |
337 | return; |
338 | } |
339 | #endif |
340 | |
341 | GCAssertMsg(false, "Trying to delete an object with FixedMalloc::Free that was not allocated with FixedMalloc::Alloc")do { } while (0); |
342 | } |
343 | |
344 | #ifndef AVMPLUS_SAMPLER |
345 | void FixedMalloc::AddToLargeObjectTracker(const void* item) |
346 | { |
347 | if (!m_heap->config.checkFixedMemory()) |
348 | return; |
349 | |
350 | LargeObject* lo = (LargeObject*)Alloc(sizeof(LargeObject)); |
351 | lo->item = item; |
352 | MMGC_LOCK(m_largeObjectLock)MMgc::GCAcquireSpinlock _lock(&m_largeObjectLock); |
353 | lo->next = largeObjects; |
354 | largeObjects = lo; |
355 | } |
356 | |
357 | void FixedMalloc::RemoveFromLargeObjectTracker(const void* item) |
358 | { |
359 | if (!m_heap->config.checkFixedMemory()) |
360 | return; |
361 | |
362 | void *loToFree=NULL__null; |
363 | { |
364 | MMGC_LOCK(m_largeObjectLock)MMgc::GCAcquireSpinlock _lock(&m_largeObjectLock); |
365 | LargeObject *lo, *prev; |
366 | for ( prev=NULL__null, lo=largeObjects ; lo != NULL__null ; prev=lo, lo=lo->next ) { |
367 | if (lo->item == item) { |
368 | if (prev != NULL__null) |
369 | prev->next = lo->next; |
370 | else |
371 | largeObjects = lo->next; |
372 | loToFree = lo; |
373 | break; |
374 | } |
375 | } |
376 | } |
377 | if(loToFree) |
378 | Free(loToFree); |
379 | } |
380 | #endif // !AVMPLUS_SAMPLER |
381 | #endif // DEBUG |
382 | } |
383 | |