gecko-dev/js/tamarin/MMgc/GCAlloc.h

402 строки
11 KiB
C
Исходник Обычный вид История

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is [Open Source Virtual Machine.].
*
* The Initial Developer of the Original Code is
* Adobe System Incorporated.
* Portions created by the Initial Developer are Copyright (C) 2004-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Adobe AS3 Team
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __GCAlloc__
#define __GCAlloc__
namespace MMgc
{
/**
*
* This is a fast, fixed-size memory allocator for garbage-collected
* objects.
*
* Memory is allocated from the system on 4096-byte aligned boundaries,
* which corresponds to the size of an OS page in Windows XP. Allocation
* of pages is performed via the GCPageAlloc class.
*
* In each 4096-byte block, there is a block header with marked bits,
* finalize bits, the pointer to the next free item and "recycling"
* free item linked list.
*
* The bits of the "marked" bitmap are controlled by the SetMark method.
*
* The bits of the "finalize" bitmap are set when an item is
* allocated. The value for the finalize bit is passed in as a
* parameter to the allocation call.
*
* When the Sweep method is invoked, all objects that are not marked
* with the specified mark flag are disposed of. If the corresponding
* finalize bit is set, the GCObject destructor is invoked on that
* item.
*
* When an allocation is requested and there are no more free
* entries, GCAlloc will request that a garbage collection take
* place. It will allocate new blocks if more than 20% of its
* blocks are used after the collection, targeting a 5:1
* heap size / minimim heap size ratio.
*
*/
class GCAlloc : public GCAllocObject
{
friend class GC;
public:
enum ItemBit { kMark=1, kQueued=2, kFinalize=4, kHasWeakRef=8, kFreelist=kMark|kQueued };
GCAlloc(GC* gc, int itemSize, bool containsPointers, bool isRC, int sizeClassIndex);
~GCAlloc();
void* Alloc(size_t size, int flags);
static void Free(void *ptr);
void Finalize();
size_t GetItemSize() { return m_itemSize; }
void ClearMarks();
#ifdef _DEBUG
void CheckMarks();
#endif
static int SetMark(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
int index = GetIndex(block, item);
int mask = kMark << ((index&7)<<2);
uint32 *bits = &block->GetBits()[index>>3];
int set = *bits & mask;
*bits |= mask;
*bits &= ~(kQueued << ((index&7)<<2));
return set;
}
static int SetQueued(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
return SetBit(block, GetIndex(block, item), kQueued);
}
static int SetFinalize(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
return SetBit(block, GetIndex(block, item), kFinalize);
}
static int IsWhite(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
// not a real item
if(item < block->items)
return false;
if(FindBeginning(item) != item)
return false;
return IsWhite(block, GetIndex(block, item));
}
static int GetMark(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
// Return the "marked" bit
return GetBit(block, GetIndex(block, item), kMark);
}
static void *FindBeginning(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
return block->items + block->size * GetIndex(block, item);
}
static void ClearFinalized(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
ClearBits(block, GetIndex(block, item), kFinalize);
}
static int IsFinalized(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
return GetBit(block, GetIndex(block, item), kFinalize);
}
static int HasWeakRef(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
return GetBit(block, GetIndex(block, item), kHasWeakRef);
}
static bool ContainsPointers(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
return block->alloc->ContainsPointers();
}
static bool IsRCObject(const void *item)
{
// Zero low 12 bits of address to get to the Block header
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
return item >= block->items && block->alloc->IsRCObject();
}
static bool IsUnmarkedPointer(const void *val);
int GetNumAlloc() const { return m_numAlloc; }
int GetMaxAlloc() const { return m_maxAlloc; }
int GetNumBlocks() const { return m_numBlocks; }
bool ContainsPointers() const { return containsPointers; }
bool IsRCObject() const { return containsRCObjects; }
void GetBitsPages(void **pages);
static void SetHasWeakRef(const void *item, bool to)
{
2006-11-15 01:15:14 +03:00
GCBlock *block = (GCBlock*) ((uintptr)item & ~0xFFF);
if(to) {
SetBit(block, GetIndex(block, item), kHasWeakRef);
} else {
ClearBits(block, GetIndex(block, item), kHasWeakRef);
}
}
private:
const static int kBlockSize = 4096;
struct GCBlock;
friend struct GCAlloc::GCBlock;
struct GCBlock
{
GC *gc;
GCBlock* next;
uint32 size;
GCAlloc *alloc;
GCBlock* prev;
char* nextItem;
void* firstFree; // first item on free list
GCBlock *prevFree;
GCBlock *nextFree;
uint32* bits;
short numItems;
bool needsSweeping:1;
bool finalizeState:1; // whether we've been visited during the Finalize stage
char *items;
int GetCount() const
{
if (nextItem) {
return GCAlloc::GetIndex(this, nextItem);
} else {
return alloc->m_itemsPerBlock;
}
}
uint32 *GetBits() const
{
return bits;
}
void FreeItem(void *item, int index);
bool IsFull() const
{
bool full = (nextItem == firstFree);
// the only time nextItem and firstFree should be equal is when they
// are both zero which is also when we are full, assert to be sure
GCAssert(!full || nextItem==0);
GCAssert(!full || numItems == alloc->m_itemsPerBlock);
return full;
}
};
// The list of chunk blocks
GCBlock* m_firstBlock;
GCBlock* m_lastBlock;
// The lowest priority block that has free items
GCBlock* m_firstFree;
// List of blocks that need sweeping
GCBlock* m_needsSweeping;
int m_itemsPerBlock;
size_t m_itemSize;
int m_numBitmapBytes;
int m_sizeClassIndex;
bool m_bitsInPage;
int m_maxAlloc;
int m_numAlloc;
int m_numBlocks;
// fast divide numbers
uint16 multiple;
uint16 shift;
bool containsPointers;
bool containsRCObjects;
bool m_finalized;
bool IsOnEitherList(GCBlock *b)
{
return b->nextFree != NULL || b->prevFree != NULL || b == m_firstFree || b == m_needsSweeping;
}
GCBlock* CreateChunk();
void UnlinkChunk(GCBlock *b);
void FreeChunk(GCBlock* b);
void AddToFreeList(GCBlock *b)
{
GCAssert(!IsOnEitherList(b));
b->prevFree = NULL;
b->nextFree = m_firstFree;
if (m_firstFree) {
GCAssert(m_firstFree->prevFree == 0 && m_firstFree != b);
m_firstFree->prevFree = b;
}
m_firstFree = b;
}
void RemoveFromFreeList(GCBlock *b)
{
GCAssert(m_firstFree == b || b->prevFree != NULL);
if ( m_firstFree == b )
m_firstFree = b->nextFree;
else
b->prevFree->nextFree = b->nextFree;
if (b->nextFree)
b->nextFree->prevFree = b->prevFree;
b->nextFree = b->prevFree = NULL;
}
void AddToSweepList(GCBlock *b)
{
GCAssert(!IsOnEitherList(b) && !b->needsSweeping);
b->prevFree = NULL;
b->nextFree = m_needsSweeping;
if (m_needsSweeping) {
GCAssert(m_needsSweeping->prevFree == 0);
m_needsSweeping->prevFree = b;
}
m_needsSweeping = b;
b->needsSweeping = true;
}
void RemoveFromSweepList(GCBlock *b)
{
GCAssert(m_needsSweeping == b || b->prevFree != NULL);
if ( m_needsSweeping == b )
m_needsSweeping = b->nextFree;
else
b->prevFree->nextFree = b->nextFree;
if (b->nextFree)
b->nextFree->prevFree = b->prevFree;
b->needsSweeping = false;
b->nextFree = b->prevFree = NULL;
}
bool Sweep(GCBlock *b);
void SweepGuts(GCBlock *b);
void ClearMarks(GCAlloc::GCBlock* block);
void SweepNeedsSweeping();
bool IsLastFreeBlock(GCBlock *b) { return m_firstFree == NULL || (m_firstFree == b && b->nextFree == NULL); }
static int ConservativeGetMark(const void *item, bool bogusPointerReturnValue);
static int GetIndex(const GCBlock *block, const void *item)
{
int index = (((char*) item - block->items) * block->alloc->multiple) >> block->alloc->shift;
#ifdef _DEBUG
GCAssert(((char*) item - block->items) / block->size == (uint32) index);
#endif
return index;
}
static int IsWhite(GCBlock *block, int index)
{
return (block->GetBits()[index>>3] & ((kMark|kQueued)<<((index&7)<<2))) == 0;
}
static int SetBit(GCBlock *block, int index, int bit)
{
int mask = bit << ((index&7)<<2);
int set = (block->GetBits()[index>>3] & mask);
block->GetBits()[index>>3] |= mask;
return set;
}
static int GetBit(GCBlock *block, int index, int bit)
{
int mask = bit << ((index&7)<<2);
return block->GetBits()[index>>3] & mask;
}
static void ClearBits(GCBlock *block, int index, int bits)
{
int mask = bits << ((index&7)<<2);
block->GetBits()[index>>3] &= ~mask;
}
void ComputeMultiplyShift(uint16 d, uint16 &muli, uint16 &shft);
protected:
GC *m_gc;
};
}
#endif /* __GCAlloc__ */