Bug Summary

File:platform/mac/avmshell/../../../MMgc/FixedMalloc.cpp
Location:line 235, column 13
Description:Assigned value is always the same as the existing value

Annotated Source Code

1/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3/* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * The Original Code is [Open Source Virtual Machine.].
17 *
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2004-2006
21 * the Initial Developer. All Rights Reserved.
22 *
23 * Contributor(s):
24 * Adobe AS3 Team
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40
41#include "MMgc.h"
42
43namespace MMgc
44{
45 // kSizeClassIndex[] is an array that lets us quickly determine the allocator
46 // to use for a given size, without division. A given allocation is rounded
47 // up to the nearest multiple of 8, then downshifted 3 bits, and the index
48 // tells us which allocator to use. (A special case is made for <= 4 bytes on
49 // 32-bit systems in FindAllocatorForSize to keep the table small.)
50
51 // Code to generate the table:
52 //
53 // const int kMaxSizeClassIndex = (kLargestAlloc>>3)+1;
54 // uint8_t kSizeClassIndex[kMaxSizeClassIndex];
55 // printf("static const unsigned kMaxSizeClassIndex = %d;\n",kMaxSizeClassIndex);
56 // printf("static const uint8_t kSizeClassIndex[kMaxSizeClassIndex] = {\n");
57 // for (int size = 0; size <= kLargestAlloc; size += 8)
58 // {
59 // int i = 0;
60 // while (kSizeClasses[i] < size)
61 // {
62 // ++i;
63 // AvmAssert(i < kNumSizeClasses);
64 // }
65 // AvmAssert((size>>3) < kMaxSizeClassIndex);
66 // kSizeClassIndex[(size>>3)] = i;
67 // if (size > 0) printf(",");
68 // if (size % (16*8) == 0) printf("\n");
69 // printf(" %d",i);
70 // }
71 // printf("};\n");
72
73#ifdef MMGC_64BIT
74 const int16_t FixedMalloc::kSizeClasses[kNumSizeClasses] = {
75 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, //0-9
76 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, //10-19
77 168, 176, 192, 208, 224, 232, 248, 264, 288, 304, //20-29
78 336, 360, 400, 448, 504, 576, 672, 800, 1008, 1344, //30-39
79 2016, //40
80 };
81
82 /*static*/ 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, //0-9
104 80, 88, 96, 104, 112, 120, 128, 144, 160, 176, //10-19
105 184, 192, 200, 208, 224, 232, 248, 264, 288, 312, //20-29
106 336, 368, 400, 448, 504, 576, 672, 808, 1016, 1352, //30-39
107 2032, //40
108 };
109
110 /*static*/ 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 // For debugging we track live large objects in a list. If there are a lot
133 // of large objects then a list may slow down debug builds too much; in that
134 // case we can move to a tree or similar structure. (It's useful to avoid using
135 // large objects in this data structure.)
136 struct FixedMalloc::LargeObject
137 {
138 const void *item; // Start of a block
139 LargeObject* next; // Next object
140 };
141#endif
142
143 /*static*/
144 FixedMalloc *FixedMalloc::instance;
145
146 void FixedMalloc::InitInstance(GCHeap* heap)
147 {
148 // The size tables above are derived based on a block size of 4096; this
149 // assert keeps us honest. Talk to Lars if you get into trouble here.
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 // Not entirely accurate, assumes large allocations using all of
212 // the last block (large ask size not stored).
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)
1
Taking false branch
226 gcheap_flags |= GCHeap::kCanFail;
227 if((flags & kZero) != 0)
2
Taking false branch
228 gcheap_flags |= GCHeap::kZero;
229
230 void *item = m_heap->Alloc(blocksNeeded, gcheap_flags);
231 if(item)
3
Taking true branch
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), /*managed=*/falsefalse);
239#endif // MMGC_HOOKS
240
241 UpdateLargeAllocStats(item, blocksNeeded);
242
243#ifdef DEBUG
244 // Fresh memory poisoning
245 if ((flags & kZero) == 0 && !RUNNING_ON_VALGRINDfalse)
246 memset(item, uint8_t(GCHeap::FXFreshPoison), size - DebugSize()0);
247
248#ifndef AVMPLUS_SAMPLER
249 // Enregister the large object
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 // If EnsureFixedMallocMemory returns and fixed-memory checking has not
313 // been disabled then item was definitely allocated by an allocator owned
314 // by this FixedMalloc. Large objects must be handled one of two ways
315 // depending on whether the sampler is operating: if it is, we can't
316 // allocate storage to track large objects (see bugzilla 533954),
317 // so fall back on a less accurate method.
318
319 void FixedMalloc::EnsureFixedMallocMemory(const void* item)
320 {
321 // For a discussion of this flag, see bugzilla 564878.
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