// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*-
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
//
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
// ACDK
//
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
//
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/sys/PagedHeap.cpp,v 1.28 2005/03/07 13:47:28 kommer Exp $
#include <acdk.h>
#include <acdk/lang/Error.h>
#include "PagedHeap.h"
#include <acdk/lang/ref/NotifyObjectEvent.h>
#include <acdk/util/logging/Log.h>
#include <acdk/lang/Integer.h>
#include "../Error.h"
#include <acdk/lang/sys/core_hashmap.h>
#include "BitmapPagedAllocator.h"
#include <map>
#include "core_prim.h"
#include "core_value_scope.h"
#include "AllocatorInternals.h"
static void* firstaddress = 0;
//#define DEBUG_PA
#define DOUTST(msgstr) sys::coreout << msgstr
#ifdef DEBUG_PA
#define DOUT(msgstr) sys::coreout << msgstr
#else //DEBUG_PA
#define DOUT(msgstr) do { } while(false)
#endif //DEBUG_PA
int hash(void* ptr, int mod)
{
if (firstaddress == 0)
firstaddress = ptr;
const char* cptr = (const char*)ptr;
int erg = 0;
for (int i = 3; i >= 0; i--) {
erg = (64 * erg + cptr[i]) % mod;
}
return erg;
#ifdef ACDK_BIGENDIAN
return int(ptr);
#else
/FONT>
return int(ptr) << 8;
#endif
/FONT>
/*//return (int)ptr;
const char* cptr = (const char*)ptr;
erg = cptr[1] + (cptr[0] >>
int erg = cptr[1];
erg = erg * 31 + cptr[0];
erg = erg * 31 + cptr[3];
return erg * 31 + cptr[2];
*/
}
int hash(const acdk::lang::RObject* ref, int tablesize)
{
return hash((void*)ref, tablesize);
}
static const acdk::lang::Object* _lastAddress = 0;
static const acdk::lang::Object* _firstAddress = 0;
static float _addressFactor = 1.0;
int hash(const acdk::lang::Object* ref, int tablesize)
{
//return hash((void*)ref, tablesize);
int offset = int(ref) - int(_firstAddress);
int erg = (int)((float)offset * _addressFactor);
if (erg > tablesize)
return erg % tablesize;
return erg;
//return hash((void*)ref, tablesize);
}
namespace acdk {
namespace lang {
namespace sys {
PagedHeap::PagedHeap(int pagesize/* = 1024*/, RHeapFrame top/* = 0*/, int flags, const char* name/* = ""*/)
: HeapFrame(top, flags | HeapHasRC | HeapHasGC | HeapTraceObjects, name)
, _allocator(new PagedAllocator(pagesize))
{
}
#define CHECK_PagedAllocatorPage(ap) if (ap == 0) break; if (ap->_magic != (short)PagedAllocatorPage::Magic) THROW1(Error, "Page is corrupt")
#define CHECK_PagedAllocatorPageSlot(ps) if (ps == 0) break; if (ps->_magic != (short)PagedAllocatorPageSlot::Magic) THROW1(Error, "PageSlot is corrupt")
#define CHECK_Object(o) if (o->magic() != _MagicObjectSig) THROW1(Error, "*** Oops invalide acdk::lang::Object Reference found")
/**
for given acdk::lang::Object* o the corresponding acdk::lang::Object* p, which has o as member
*/
ReferedMap* ReferedMap::_thisInstance = 0;
/**
A multimap, which holds for each acdk::lang::Object o the acdk::lang::Object, which holds o
class HolderMap
{
core_flathashmap<acdk::lang::Object*, ObjectRefPtrVector*> _map;
public:
static HolderMap* _thisInstance;
typedef core_flathashmap<acdk::lang::Object*, ObjectRefPtrVector*>::iterator iterator;
HolderMap(int mapsize)
: _map(mapsize, false)
{
_thisInstance = this;
}
~HolderMap()
{
_thisInstance = 0;
}
void add(acdk::lang::Object* reference)
{
add(reference->impl(), reference);
}
void add(acdk::lang::Object* obj, acdk::lang::Object* reference)
{
ObjectRefPtrVector** orgvec = _map.get(obj);
if (orgvec != 0) {
(*orgvec)->push_back(reference);
} else {
ObjectRefPtrVector* _vec = new ObjectRefPtrVector(3);
_vec->push_back(reference);
_map.put(obj, _vec);
}
}
iterator begin() { return _map.begin(); }
iterator end() { return _map.end(); }
iterator find(acdk::lang::Object* obj) { return _map.find(obj); }
void erase(const iterator& it) { _map.erase(it); }
void eraseValue(acdk::lang::Object* ref)
{
if (ref->impl() == 0 || _map.find(ref->impl()) == _map.end())
return;
iterator it = begin();
iterator et = end();
if (it != et && it.value() != 0) {
ObjectRefPtrVector& orgvec = *it.value();
for (int i = 0; i < orgvec.size(); i++) {
if (orgvec[i] == ref)
orgvec[i] = 0;
}
}
}
void dumpRef();
};
HolderMap* HolderMap::_thisInstance = 0;
*/
class PagedHeap_ObjectDestroyListener
: public acdk::lang::Object,
implements acdk::lang::ref::NotifyObjectEventListener
{
ReferedMap& _refmap;
public:
PagedHeap_ObjectDestroyListener(ReferedMap& refmap)
: _refmap(refmap)
{
}
virtual void notifyBeforeConstruction(acdk::lang::Object* obj) { }
virtual bool notifyBeforeDestruction(acdk::lang::Object* obj)
{
ReferedMap::iterator it = _refmap.find(obj);
if (it != _refmap.end())
_refmap.erase(it);
return true;
}
virtual void notifyWhileDestruction(acdk::lang::Object* obj) { }
virtual bool listHeaps(IN(::acdk::lang::sys::RHeapFrame) theheap) { return false; }
virtual bool listedAllocated(IN(::acdk::lang::sys::RHeapFrame) theheap, void* obj, AllocatedType type) { return false; }
};
class PagedAllocatorObjectsIterator
: public AllocatorObjectsIterator
{
PagedAllocator* _allocator;
PagedAllocatorPage* _page;
PagedAllocatorPageSlot* _slot;
PagedAllocatorPageSlot* _currentSlot;
bool _hasNext;
/// see ListObjectsFlags
int _searchFlags;
public:
PagedAllocatorObjectsIterator(PagedAllocator* pagedAllocator, int searchFlags = ObjectMem)
: _allocator(pagedAllocator)
, _page(_allocator->_first)
, _slot(_page->_first)
, _currentSlot(0)
, _hasNext(true)
, _searchFlags(searchFlags)
{
}
virtual void* getNext()
{
return seekNext();
}
virtual acdk::lang::Object* getNextObject()
{
if (_searchFlags & ObjectMem)
{
if (seekNext() == 0)
return 0;
return _currentSlot->_getObject();
}
core_value_scope<int> sf(_searchFlags, (_searchFlags & ~AllocatedTypeMask) | ObjectMem);
if (seekNext() == 0)
return 0;
return _slot->_getObject();
}
void reset()
{
_page = _allocator->_first;
_slot = _page->_first;
_hasNext = true;
}
void _nextSlot()
{
bool checkNextPage = false;
if (_slot->_next == _slot)
checkNextPage = true;
_slot = _slot->_next;
if (checkNextPage == true || _slot == _page->_first || _slot == 0)
{
_page = _page->_next;
if (_page == _allocator->_first || _page == 0)
{
_hasNext = false;
}
else
_slot = _page->_first;
}
}
void* seekNext()
{
if (_hasNext == false)
return 0;
do {
if (_page == 0)
break;
if (_slot == 0)
break;
int sf = _searchFlags & AllocatedTypeMask;
if (sf == 0 || (sf & _slot->_flags))
{
if (_slot->_flags & ObjectMem)
{
acdk::lang::Object* o = _slot->_getObject();
DOUT("O: " << (void*)o << sys::eofl);
if (o->magic() == _MagicObjectSig)
{
_currentSlot = _slot;
_nextSlot();
return o;
}
}
else
{
_currentSlot = _slot;
_nextSlot();
return _currentSlot->mem();
}
}
_nextSlot();
} while (_hasNext == true);
//_hasNext = false;
//_currentSlot = 0;
return 0;
}
AllocatorElement getCurrentElement()
{
if (_currentSlot == 0)
return AllocatorElement();
if (_currentSlot->_flags & ObjectMem)
return AllocatorElement(_currentSlot->_getObject(), _currentSlot->_size, _currentSlot->_size + ALIGNEDSIZEOF(PagedAllocatorPageSlot));
return AllocatorElement(_currentSlot->mem(), _currentSlot->_flags, _currentSlot->_size, _currentSlot->_size + ALIGNEDSIZEOF(PagedAllocatorPageSlot));
}
};
//virtual
bool
PagedHeap::gc(bool recursiv/* = true */)
{
PAGELOCK();
PagedAllocatorObjectsIterator pait(_allocator, ObjectMem);
_allocator->_heap = this;
bool bret = doGc(_allocator, &pait, recursiv);
_allocator->_heap = 0;
return bret;
}
//virtual
bool
PagedHeap::onDestroy(acdk::lang::Object* obj)
{
if (ReferedMap::_thisInstance == 0)
return true;
//DOUT("GC: ~obj: " << (void*) obj << sys::eofl);
ReferedMap::iterator it = ReferedMap::_thisInstance->find(obj);
if (it != ReferedMap::_thisInstance->end())
ReferedMap::_thisInstance->erase(it);
else
DOUT("~obj not found: " << (void*) obj << sys::eofl);
return true;
/** really needed??
int colfields = const_cast<acdk::lang::Object*>(obj)->getClazzInfo()->_collectableFieldsCount();
if (colfields == 0)
return true;
FieldReferences fields;
const_cast<acdk::lang::Object*>(obj)->getCollectableFields(fields);
for (int i = 0; i < fields.size(); i++) {
if (*fields[i] != Nil) {
ReferedMap::_thisInstance->eraseValue(fields[i]);
}
}
return true;
*/
}
//virtual
void
PagedHeap::listObjects(::acdk::lang::ref::NotifyObjectEventListener* listener, int flags)
{
if (flags & ListRootsOnly)
flags |= ObjectMem;
PAGELOCK();
PagedAllocatorObjectsIterator pait(_allocator, flags);
genericListObject(this, &pait, listener, flags);
/*
acdk::lang::Object* o = 0;
if (flags & ListRootsOnly)
{
PAGELOCK();
markMemberObjects(&pait);
}
pait.reset();
while (pait.getNext() != 0)
{
AllocatorElement el = pait.getCurrentElement();
if (el.type == ObjectMem)
o = el.mem.obj;
else
o = 0;
if ((flags & ListRootsOnly) == 0 || (o != 0 && o->_isObjectRefFlag(ObjectBase::Marked) == false))
{
if (listener->listedAllocated(this, el.mem.buffer, (AllocatedType)(AllocatedTypeMask & el.type), el.size) == false)
return;
}
}
*/
if ((flags & ListObjectsRecursive) == 0)
return;
if (_top == 0)
return;
_top->listObjects(listener, flags);
}
} // namespace sys
} // namespace lang
} // namespace acdk
|