root/MMgc/GCAlloc-inlines.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
/* ***** 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_inlines__
#define __GCAlloc_inlines__

// Inline functions for GCAlloc, GCAlloc::GCBlock, and GCAllocIterator

namespace MMgc
{
        REALLY_INLINE GCBlockHeader* GetBlockHeader(const void* item)
        {
                return (GCBlockHeader*)(uintptr_t(item) & ~0xFFF);
        }

        /*static*/
        REALLY_INLINE GCAlloc::GCBlock *GCAlloc::GetBlock(const void *item)
        { 
                return (GCBlock*)GetBlockHeader(item);
        }
        
        /*static*/
        REALLY_INLINE GCAlloc::GCBlock* GCAlloc::Next(GCAlloc::GCBlock* b)
        {
                return (GCBlock*)b->next;
        }
        
        REALLY_INLINE int GCAlloc::SetMark(const void *item)
        {
                GCBlock *block = GetBlock(item);
                int index = GetIndex(block, item);
                int mask = kMark << ((index&7)<<2);
                uint32_t *bits = &block->GetBits()[index>>3];
                int set = *bits & mask;
                *bits |= mask;
                *bits &= ~(kQueued << ((index&7)<<2));
                return set;
        }

        /*static*/
        REALLY_INLINE int GCAlloc::SetFinalize(const void *item)
        {
                GCBlock *block = GetBlock(item);
                return SetBit(block, GetIndex(block, item), kFinalize);
        }

        /*static*/
        REALLY_INLINE int GCAlloc::GetMark(const void *item)
        {
                GCBlock *block = GetBlock(item);
                return GetBit(block, GetIndex(block, item), kMark);
        }

        /*static*/
        REALLY_INLINE void *GCAlloc::FindBeginning(const void *item)
        {
                GCBlock *block = GetBlock(item);
                return block->items + block->size * GetIndex(block, item);
        }

        /*static*/
        REALLY_INLINE bool GCAlloc::IsMarkedThenMakeQueued(const void *item)
        {
                GCBlock *block = GetBlock(item);
                int index = GetIndex(block, item);
                uint32_t* bits = block->GetBits() + (index >> 3);
                if (*bits & (kMark << ((index&7)<<2))) {
                        *bits ^= (kMark|kQueued) << ((index&7)<<2);
                        return true;
                }
                return false;
        }

        /*static*/
        REALLY_INLINE bool GCAlloc::IsQueued(const void *item)
        {
                GCBlock *block = GetBlock(item);
                int index = GetIndex(block, item);
                uint32_t* bits = block->GetBits() + (index >> 3);
                return (*bits & (kQueued << ((index&7)<<2))) != 0;
        }

        /*static*/
        REALLY_INLINE void GCAlloc::ClearFinalized(const void *item)
        {
                GCBlock *block = GetBlock(item);
                ClearBits(block, GetIndex(block, item), kFinalize);
        }               

        /*static*/
        REALLY_INLINE int GCAlloc::IsFinalized(const void *item)
        {
                GCBlock *block = GetBlock(item);
                return GetBit(block, GetIndex(block, item), kFinalize);
        }

        /*static*/
        REALLY_INLINE int GCAlloc::HasWeakRef(const void *item)
        {
                GCBlock *block = GetBlock(item);
                return GetBit(block, GetIndex(block, item), kHasWeakRef);
        }               
        
        /*static*/
        REALLY_INLINE bool GCAlloc::ContainsPointers(const void *item)
        {
                GCBlock *block = GetBlock(item);
                return block->alloc->ContainsPointers();
        }

        /*static*/
        REALLY_INLINE bool GCAlloc::IsRCObject(const void *item)
        {
                GCBlock *block = GetBlock(item);
                return item >= block->items && block->alloc->ContainsRCObjects();
        }

        /*static*/
        REALLY_INLINE void GCAlloc::SetHasWeakRef(const void *item, bool to)
        {
                GCBlock *block = GetBlock(item);
                if(to) {
                        SetBit(block, GetIndex(block, item), kHasWeakRef);
                } else {
                        ClearBits(block, GetIndex(block, item), kHasWeakRef);
                }
        }
        
        REALLY_INLINE void GCAlloc::AddToFreeList(GCBlock *b)
        {
                GCAssert(!IsOnEitherList(b) && !b->needsSweeping);
                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;                        
        }

        REALLY_INLINE void GCAlloc::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;
        }

        REALLY_INLINE void GCAlloc::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;
        }

        REALLY_INLINE void GCAlloc::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;
        }

        /*static*/
        REALLY_INLINE int GCAlloc::GetIndex(const GCBlock *block, const void *item)
        {
                int index = (int)((((char*) item - block->items) * block->alloc->multiple) >> block->alloc->shift);
#ifdef _DEBUG
                GCAssert(((char*) item - block->items) / block->size == (uint32_t) index);
#endif
                return index;
        }                       
        
        /*static*/
        REALLY_INLINE int GCAlloc::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*/
        REALLY_INLINE int GCAlloc::GetBit(GCBlock *block, int index, int bit)
        {
                int mask = bit << ((index&7)<<2);
                return block->GetBits()[index>>3] & mask;
        }
        
        /*static*/
        REALLY_INLINE void GCAlloc::ClearBits(GCBlock *block, int index, int bits)
        {
                int mask = bits << ((index&7)<<2);
                block->GetBits()[index>>3] &= ~mask;
        }
        
        /*static*/
        REALLY_INLINE void GCAlloc::Clear4BitsAndSet(GCBlock *block, int index, int bit)
        {
                uint32_t *bitp = &(block->GetBits()[index>>3]);
                *bitp = (*bitp & ~(15 << ((index & 7) << 2))) | (bit << ((index & 7) << 2));
        }
        
        /*static*/
        REALLY_INLINE void GCAlloc::ClearQueued(const void *item)
        {
                GCBlock *block = GetBlock(item);
                ClearBits(block, GetIndex(block, item), kQueued);
        }
        
#ifdef _DEBUG
        /*static*/
        REALLY_INLINE bool GCAlloc::IsPointerIntoGCObject(const void *item)
        {
                GCBlock *block = GetBlock(item);
                if(item < block->items)
                        return false;
                return GetBit(block, GetIndex(block, item), kFreelist) != kFreelist;
        }
        
        /*static*/
        REALLY_INLINE bool GCAlloc::IsWhite(GCBlock *block, int index)
        {
                return (block->GetBits()[index>>3] & ((kMark|kQueued)<<((index&7)<<2))) == 0;
        }

        /*static*/
        REALLY_INLINE bool GCAlloc::IsWhite(const void *item)
        {
                GCBlock *block = GetBlock(item);
                // not a real item
                if(item < block->items)
                        return false;
                
                if(FindBeginning(item) != item)
                        return false;
                
                return IsWhite(block, GetIndex(block, item));
        }
        
        REALLY_INLINE bool GCAlloc::IsOnEitherList(GCBlock *b)
        {
                return b->nextFree != NULL || b->prevFree != NULL || b == m_firstFree || b == m_needsSweeping;
        }
#endif // _DEBUG
        

        REALLY_INLINE int GCAlloc::GCBlock::GetCount() const
        {
                if (nextItem) {
                        return GCAlloc::GetIndex(this, nextItem);
                } else {
                        return alloc->m_itemsPerBlock;
                }
        }

        REALLY_INLINE uint32_t *GCAlloc::GCBlock::GetBits() const
        {
                return bits;
        }

        REALLY_INLINE bool GCAlloc::GCBlock::IsFull()
        {
                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;
        }

        REALLY_INLINE GCAllocIterator::GCAllocIterator(MMgc::GCAlloc* alloc) 
                : alloc(alloc)
                , block(alloc->m_firstBlock)
                , idx(0)
                , limit(alloc->m_itemsPerBlock)
                , size(alloc->m_itemSize)
        {
        }
                
        REALLY_INLINE bool GCAllocIterator::GetNextMarkedObject(void*& out_ptr, uint32_t& out_size)
        {
                for (;;) {
                        if (idx == limit) {
                                idx = 0;
                                block = GCAlloc::Next(block);
                        }
                        if (block == NULL)
                                return false;
                        uint32_t i = idx++;
                        if (GCAlloc::GetBit(block, i, MMgc::GCAlloc::kMark) && !GCAlloc::GetBit(block, i, MMgc::GCAlloc::kQueued)) {
                                out_ptr = GetUserPointer(block->items + i*size);
                                out_size = size - (uint32_t)DebugSize();
                                return true;
                        }
                }
        }
}

#endif /* __GCAlloc_inlines__ */

/* [<][>][^][v][top][bottom][index][help] */