// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*-
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// ALL RIGHTS RESERVED
//
// This file is part of ACDK.
// artefaktur provides this software "as is" without express or implied warranty.
// Any commercial use of this software requires a license.
//
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/sys/ObjectHeap.cpp,v 1.52 2005/05/02 23:12:27 kommer Exp $
#include <acdk.h>
#include "sys.h"
#include "ObjectHeap.h"
#include "RC_Heap.h"
#include "RC_GC_Heap.h"
#include "Garbage_Heap.h"
#include "PagedHeap.h"
#include "BoehmGCAllocator.h"
#include "BitmapPagedAllocator.h"
#include "../ref/ref.h"
#if defined(__BORLANDC__)
# include <malloc.h>
#endif //!defined(__BORLANDC__)
#include <stdio.h>
#include <acdk/lang/System.h>
#include <acdk/lang/Exception.h>
#include <acdk/lang/sys/core_mutex.h>
#include <acdk/lang/sys/core_fastmutex.h>
#include <acdk/lang/ThreadLocalImpl.h>
#include <acdk/lang/ThreadImpl.h>
#include "core_specific.h"
#include "core_syslocal.h"
namespace acdk {
namespace lang {
namespace dmi {
void ClazzInfo_deinit();
}
namespace sys {
using namespace acdk::lang;
#define DOUT(msg)
//#define DOUT(msg) sys::coreout << msg << sys::eofl
core_vector<SysObject*>&
sysObjects()
{
static core_vector<SysObject*> _sysObjects;
return _sysObjects;
}
void cleanup_system_objects()
{
}
//static
jlong&
ObjectHeap::threadMaxMemoryUsage()
{
static sys::specific<jlong> _threadMaxMemory;
if (core_system::inMain() == false)
return maxMemoryUsage();
if (_threadMaxMemory.isSet() == false)
_threadMaxMemory = 1024 * 1024 * 1024;
return _threadMaxMemory.get();
}
//static
jlong&
ObjectHeap::maxMemoryUsage()
{
static jlong MaxMemoryUsage = 1024 * 1024 * 1024; // 1 GB
return MaxMemoryUsage;
jlong& thr = threadMaxMemoryUsage();
return MaxMemoryUsage < thr ? MaxMemoryUsage : thr;
return threadMaxMemoryUsage();
}
//static
jlong&
ObjectHeap::curMemUsage()
{
static jlong CurMemUsage = 0;
return CurMemUsage;
}
//static
jlong&
ObjectHeap::curThreadMemUsage()
{
static sys::specific<jlong> _threadCurMemory;
if (core_system::inMain() == false)
return curMemUsage();
if (_threadCurMemory.isSet() == false)
_threadCurMemory = 0;
return _threadCurMemory.get();
}
SysObject::SysObject()
: _refCount(0)
{
DOUT("SysObject::SysObject(" << (void*) this << ")");
if (System::isInMain() == false)
return;
sysObjects().push_back(this);
}
SysObject::~SysObject()
{
DOUT("SysObject::~SysObject(" << (void*) this << ")");
if (System::isInMain() == false)
return;
for (int i = 0; i < sysObjects().size(); i++)
{
if (sysObjects()[i] == this) {
sysObjects()[i] = 0;
break;
}
}
}
void
SysObject::releaseRef() const
{
/*
DOUT("SysObject::releaseRef(" << (void*) this << ", " << _refCount.read() << ")");
if (_refCount.decr_test_zero() == true) {
delete const_cast<SysObject*>(this);
}*/
}
void
SysObject::addRef() const
{
//DOUT("SysObject::increment(" << (void*) this << ", " << _refCount.read() << ")");
//_refCount.increment();
}
void
HeapLockMutex::lock()
{
if (acdk::lang::System::isInMain() == true)
static_mutex::lock();
}
void
HeapLockMutex::unlock()
{
if (acdk::lang::System::isInMain() == true)
static_mutex::unlock();
}
#ifdef ACDK_MT
HeapLockMutex _heapAccessLock;
#endif // ACDK_MT
/** thread-neutral heap */
RHeapFrame& _getTopFrame()
{
static RHeapFrame __topFrame;// = new RC_GC_Heap();
return __topFrame;
}
RHeapFrame _getStaticObjectsFrame()
{
static RHeapFrame __staticObjectsFrame;
return __staticObjectsFrame;
}
DEFINE_STATIC_SPECIFIC(RHeapFrame*, _topHeapStaticSpecific);
static_specific<RHeapFrame>& thrTopHeap()
{
static static_specific<RHeapFrame> _th(core_system::acdk_core_static_bound, &_topHeapStaticSpecific);
return _th;
}
/*
ThreadLocalImpl& thrTopHeap()
{
static ThreadLocalImpl _thrTopHeap;
return _thrTopHeap;
}
*/
core_vector<RHeapFrame>& allHeaps()
{
static core_vector<RHeapFrame> _allHeaps;
return _allHeaps;
}
//static
void
SysObject::_throwNullPointerException()
{
::acdk::lang::ObjectBase::_throwNullPointerException("SysObject");
}
HeapFrame::HeapFrame(RHeapFrame top/* = 0*/, int flags/* = HeapIsThread*/, const char* name/* = ""*/)
: _top(top),
_name(name),
_flags(flags),
_threadId()
{
DOUT("HeapFrame::HeapFrame(" << (void*) this << ")");
if (_flags & HeapIsThread)
_threadId = (int)ThreadID::getCurrentThreadID().threadID();
//allHeaps().push_back(this);
}
//virtual
HeapFrame::~HeapFrame()
{
//sys::coreout << "HeapFrame::~HeapFrame() [" << _name.c_str() << "] id=[" << _threadId << "]" << sys::eofl;
}
//virtual
bool
HeapFrame::_setInFieldToNil(const acdk::lang::Object* obj, bool recursiv)
{
if (recursiv == true && up() != 0)
return up()->_setInFieldToNil(obj, recursiv);
return false;
}
void _setTopFrame(RHeapFrame h)
{
if (allHeaps().hasElement(h) == false)
allHeaps().push_back(h);
if (h->flags() & HeapIsGlobal || ::acdk::lang::System::isInMain() == false)
{
_getTopFrame() = h;
}
else if (h->flags() & HeapIsThread)
{
RHeapFrame& oldheap = thrTopHeap().get();
oldheap = h;
/* old
RHeapFrame oldheap = (RHeapFrame)(HeapFrame*)thrTopHeap().get();
if (oldheap != Nil)
oldheap->releaseRef();
thrTopHeap().set((HeapFrame*)h);
*/
if (h != Nil)
h->addRef();
} else
_getStaticObjectsFrame() = h;
}
void setTopFrame(RHeapFrame h)
{
DOUT("setTopFrame(" << (void*) h.impl() << ")");
if (System::isInMain() == false)
{
DOUT("isInMain is false(" << (void*) h.impl() << ")");
_getStaticObjectsFrame() = h;
_getTopFrame() = h;
return;
}
HEAPLOCKGUARD();
_setTopFrame(h);
}
void removeFrame(RHeapFrame h)
{
allHeaps().deleteElement(h);
core_vector< RHeapFrame>::iterator it = allHeaps().begin();
core_vector< RHeapFrame>::iterator end = allHeaps().end();
while (it != end)
{
RHeapFrame f = *it;
if (f == h)
sys::coreout << "Oops removeFrame" << __FILE__ << ":" << __LINE__ << sys::eofl;
++it;
}
h->dispose();
}
RHeapFrame topFrame()
{
// ### old code. current should work for all platforms.
//#if (defined(ACDK_OS_WIN32) && defined(ACDK_STATIC_LIB)) || defined(ACDK_OS_UNIX)
if (::acdk::lang::System::isInMain() == false)
return _getTopFrame();
//#endif
RHeapFrame h = (RHeapFrame)(HeapFrame*)thrTopHeap().get();
//sys::coreout << "topframe is " << (void*)(HeapFrame*)h << sys::eofl;
if (h == 0)
return _getTopFrame();
return h;
}
RHeapFrame staticObjectsFrame()
{
if (_getStaticObjectsFrame() != 0)
return _getStaticObjectsFrame();
_getStaticObjectsFrame() = new acdk::lang::sys::RC_GC_Heap(topFrame(), HeapIsStatic, "Statics");
return _getStaticObjectsFrame();
}
namespace {
class LastOnHeapAllocated;
DEFINE_STATIC_SPECIFIC(LastOnHeapAllocated*, _staticSecificLastOnHeap);
enum {
MAX_NEW_STACK = 32
};
class LastOnHeapAllocated
{
acdk::lang::Object* _allocatedStack[MAX_NEW_STACK];
int _top;
public:
LastOnHeapAllocated()
{
_top = -1;
memset(_allocatedStack, 0, sizeof(_allocatedStack));
}
/**
this version is used if not already initialized
*/
static LastOnHeapAllocated& _static()
{
static LastOnHeapAllocated _loh;
return _loh;
}
~LastOnHeapAllocated()
{
}
inline bool _fetch(acdk::lang::Object* obj)
{
if (_top == -1)
return false;
if (_allocatedStack[_top] == obj) {
--_top;
return true;
}
return false;
}
inline void _put(acdk::lang::Object* obj)
{
#if defined(ACDK_DEBUG)
if (_top >= MAX_NEW_STACK)
THROW1(Error, "Max object allocation recursion reached");
#endif
/FONT>
_allocatedStack[++_top] = obj;
}
//static sys::specific<LastOnHeapAllocated> _lastObjectOnHeap;
static void put(acdk::lang::Object* obj);
static bool fetch(acdk::lang::Object* obj);
};
static_specific<LastOnHeapAllocated>&
getSLOH()
{
static static_specific<LastOnHeapAllocated> _lastObjectOnHeap(core_system::acdk_core_static_bound, &_staticSecificLastOnHeap);
return _lastObjectOnHeap;
}
//static
void
LastOnHeapAllocated::put(acdk::lang::Object* obj)
{
getSLOH().get()._put(obj);
}
//static
bool
LastOnHeapAllocated::fetch(acdk::lang::Object* obj)
{
return getSLOH().get()._fetch(obj);
}
//DEFINE_STATIC_SPECIFIC(LastOnHeapAllocated, _lastOnHeapThreadStatic);
//sys::specific<LastOnHeapAllocated> LastOnHeapAllocated::_lastObjectOnHeap;
void ensureFrame2();
inline
void
ensureFrame()
{
if (topFrame() == Nil)
ensureFrame2();
}
void
ensureFrame2()
{
switch (System::defaultHeapType)
{
case ObjectHeap::PA_Heap :
setTopFrame(new PagedHeap());
break;
case ObjectHeap::RC_Heap:
setTopFrame(new RC_Heap());
break;
case ObjectHeap::RC_GC_Heap:
setTopFrame(new RC_GC_Heap());
break;
case ObjectHeap::GC_Heap:
if (System::isInMain() == true)
setTopFrame(new BoehmGCHeapFrame());
else
setTopFrame(new RC_GC_Heap());
break;
default:
sys::coreout << "unknown heap type" << sys::eofl;
setTopFrame(new PagedHeap());
}
}
} // anon namespace
static ThreadLocalImpl _stackBase;
void
ObjectHeap::saveStackBase(unsigned int sp)
{
_stackBase.set((void*)sp);
}
unsigned int
ObjectHeap::stackBase()
{
return (unsigned int)_stackBase.get();
}
// #### make them inlines
//static
RHeapFrame
ObjectHeap::globalHeap()
{
return _getTopFrame();
}
//static
RHeapFrame
ObjectHeap::staticHeap()
{
return _getStaticObjectsFrame();
}
RHeapFrame
ObjectHeap::getThreadLocalHeap()
{
static RHeapFrame __thrlocalheap = new acdk::lang::sys::RC_GC_Heap(topFrame(), HeapIsStatic, "ThreadLocals");
return __thrlocalheap;
}
//static
Allocator*
ObjectHeap::getThreadLocalAllocator()
{
return getThreadLocalHeap()->allocator();
}
// stores thread specific base stack address
//ThreadLocalImpl __baseStackAddress;
//static
void
ObjectHeap::newHeapObject(acdk::lang::Object* obj) // ### inline this have to be reviewed!
{
LastOnHeapAllocated::put(obj);
}
//static
bool
ObjectHeap::onHeapAllocated(acdk::lang::Object* obj)
{
return LastOnHeapAllocated::fetch(const_cast<acdk::lang::Object*>(obj));
/* no longer supported, because not all cases are regarded
acdk::lang::Object getObject()
{
static String s("asdf");
return &s; // oops mean that it is allocated on heap!
}
#if !defined(ACDK_OS_WIN32) && !defined(ACDK_OS_LINUX) && !defined(ACDK_OS_SOLARIS)
HEAPLOCKGUARD(); // is this ever needed?
#endif
//unsigned int basicEsp = (unsigned int)__baseStackAddress.get();
unsigned int basicEsp = System::getStackBase();
if (basicEsp == 0) {
//__baseStackAddress.set((void*)_getSP());
return false;
}
unsigned int curesp = _getSP();
unsigned int objadr = (unsigned int)obj;
if (objadr > curesp && objadr <= basicEsp)
return false;
return true;
*/
}
//static
bool
ObjectHeap::notifyBeforeObjectDestruction(acdk::lang::Object* obj)
{
HEAPLOCKGUARD();
return ::acdk::lang::ref::NotifyObjectEvent::notifyBeforeDestruction(obj);
}
//static
void
ObjectHeap::notifyWhileObjectDestruction(acdk::lang::Object* obj)
{
HEAPLOCKGUARD();
::acdk::lang::ref::NotifyObjectEvent::notifyWhileDestruction(obj);
}
//static
acdk::lang::Object*
ObjectHeap::_newStaticObject(acdk::lang::Object* obj)
{
//_removeObject(obj);
//staticObjectsFrame()->add(obj, 0);
return obj;
}
typedef core_vector<acdk::lang::Object*> ReferencePointerVector;
ReferencePointerVector&
getStaticReferences()
{
static ReferencePointerVector _staticObjectReferences;
return _staticObjectReferences;
}
//static
void
ObjectHeap::registerStaticReference(RefHolder<acdk::lang::Object>* reference)
{
HEAPLOCKGUARD();
getStaticReferences().push_back(reference);
/* ### @todo dont do anything
HEAPLOCKGUARD();
_newStaticObject(const_cast<acdk::lang::Object*>(reference->impl()));
if (reference->impl() == 0)
return;
reference->impl()->setStaticRef(true); // use impl not iptr, because it may be a forced cased from an Interface
//deprevated: reference->impl()->setInterThreadReference(true); // use impl not iptr, because it may be a forced cased from an Interface
_staticObjectReferences.push_back(reference);
*/
}
//static
bool
ObjectHeap::isStaticReferenceObject(acdk::lang::Object* obj)
{
HEAPLOCKGUARD();
ReferencePointerVector& refvec = getStaticReferences();
ReferencePointerVector::iterator it = refvec.begin();
ReferencePointerVector::iterator end = refvec.end();
for (; it != end; ++it)
{
if ((*it)->impl() == obj)
return true;
}
return false;
}
//static
void
ObjectHeap::registerStaticReference(acdk::lang::Object* reference)
{
/** ### @todo dont do anything
HEAPLOCKGUARD();
if (reference == 0)
return;
_newStaticObject(reference);
reference->setStaticRef(true);
*/
}
//static
void
ObjectHeap::clearAllStaticReferences()
{
//don't do this here, HEAPLOCKGUARD();
return;
ReferencePointerVector& refvec = getStaticReferences();
ReferencePointerVector::iterator it = refvec.begin();
ReferencePointerVector::iterator end = refvec.end();
while (it != end) {
if ((*it) != 0 && _valid((*it)->impl())) {
RefHolder<acdk::lang::Object>* tobj = (*it);
if (*tobj != Nil)
{
//sys::coreout << "clear static reference: " << (void*) tobj->iptr() << sys::eofl; //": " << (*tobj)->toString()->c_str() << sys::eofl;
*tobj = Nil;
//sys::coreout << "cleared static reference: " << sys::eofl;
}
}
++it;
}
::acdk::lang::dmi::ClazzInfo_deinit();
// crashes with new acdk::lang::Object _staticObjectsFrame->removeAllStaticReferences();
}
//static
Allocator*
ObjectHeap::allocator()
{
ensureFrame();
HeapFrame* tf = topFrame();
if (tf == 0)
{
int *tptr = 0;
*tptr = 42;
tf = topFrame();
}
return tf->allocator();
}
//static
Allocator*
getThreadLocalAllocator();
//static
int
ObjectHeap::objectCount(bool total)
{
HEAPLOCKGUARD();
//### implement me
return 0;
}
//static
size_t
ObjectHeap::totalAllocated(bool total)
{
HEAPLOCKGUARD();
//### implement me
return 0;
}
//static
bool
ObjectHeap::gc(bool total)
{
HEAPLOCKGUARD();
HeapFrame *top = topFrame();
if (top == 0)
return false;
bool erg = false;
{
//UNLOCKHEAPGUARD();
erg = top->gc(false);
}
if (total == false)
return erg;
core_vector<RHeapFrame>::iterator it = allHeaps().begin();
core_vector<RHeapFrame>::iterator end = allHeaps().begin();
while (it != end)
{
if (*it != top)
{
//UNLOCKHEAPGUARD();
erg |= (*it)->gc(false);
}
++it;
}
return erg;
}
//static
void
ObjectHeap::pushFrame(RHeapFrame heap)
{
HEAPLOCKGUARD();
_setTopFrame(heap);
}
//static
void
ObjectHeap::pushFrame(HeapType heaptype, HeapInfo info, const char* name)
{
HEAPLOCKGUARD();
switch(heaptype)
{
case PA_Heap:
_setTopFrame(new acdk::lang::sys::PagedHeap(4096, topFrame(), info, name));
break;
case RC_Heap :
_setTopFrame(new acdk::lang::sys::RC_Heap(topFrame(), info, name));
break;
case RC_GC_Heap:
_setTopFrame(new acdk::lang::sys::RC_GC_Heap(topFrame(), info, name));
break;
case Garbage_Heap :
_setTopFrame(new acdk::lang::sys::Garbage_Heap(topFrame(), info, name));
break;
case GC_Heap :
if (System::isInMain() == true)
_setTopFrame(new acdk::lang::sys::BoehmGCHeapFrame(topFrame(), info, name));
else
_setTopFrame(new acdk::lang::sys::RC_GC_Heap(topFrame(), info, name));
break;
case Private_Heap :
// no break
default:
THROW1(Exception, "ObjectHeap::pushFrame() given HeapType not supported");
break;
}
}
/* removes the Heap connected with this thread */
void
ObjectHeap::removeThreadHeap()
{
RHeapFrame& oldtop = thrTopHeap().get();
if (oldtop == Nil)
return;
removeFrame(oldtop);
oldtop = Nil;
/* old
RHeapFrame oldtop = (RHeapFrame)(HeapFrame*)thrTopHeap().get();
if (oldtop == Nil)
return;
removeFrame(oldtop);
thrTopHeap().set(0);
*/
//## will gpf' oldtop->releaseRef();
}
//static
void
ObjectHeap::popFrame(HeapInfo info)
{
HEAPLOCKGUARD();
RHeapFrame oldtop;
if (info == HeapIsGlobal || ::acdk::lang::System::isInMain() == false)
oldtop = _getTopFrame();
else if (info == HeapIsThread)
oldtop = (RHeapFrame)(HeapFrame*)thrTopHeap().get();
else
THROW1(Exception, RString("Unsupported HeapFrame type in ObjectHeap::popFrame(HeapInfo info):") + info);
if (oldtop == 0) {
THROW1(Exception, RString("Unsupported HeapFrame type in ObjectHeap::popFrame(HeapInfo info):") + info);
//sys::coreout << "acdk::lang::sys::ObjectHeap::popFrame() called without an active Frame" << sys::eofl;
return;
}
RHeapFrame newTop = oldtop->up();
//if (newTop != Nil)
//{
oldtop->setUpFrame(Nil);
if (newTop != Nil)
_setTopFrame(newTop);
removeFrame(oldtop);
//}
}
//static
RHeapFrame
ObjectHeap::topHeapFrame()
{
HEAPLOCKGUARD();
return topFrame();
}
//static
void
ObjectHeap::listHeaps(::acdk::lang::ref::NotifyObjectEventListener* listener, bool allthreads)
{
HEAPLOCKGUARD();
core_vector<RHeapFrame>::iterator it = allHeaps().begin();
core_vector<RHeapFrame>::iterator end = allHeaps().end();
while (it != end) {
RHeapFrame tf = *it;
if (listener->listHeaps(tf) == false)
break;
++it;
}
}
//static
void
ObjectHeap::listObjects(::acdk::lang::ref::NotifyObjectEventListener* listener, int flags)
{
if (flags & ListObjectsRecursive)
{
int sf = flags & ~ListObjectsRecursive;
topHeapFrame()->listObjects(listener, sf);
core_vector<RHeapFrame>::iterator it = allHeaps().begin();
core_vector<RHeapFrame>::iterator end = allHeaps().end();
while (it != end)
{
RHeapFrame tf = *it;
tf->listObjects(listener, sf);
++it;
}
}
else
{
topHeapFrame()->listObjects(listener, flags);
}
}
//static
void
ObjectHeap::listedAllocated(::acdk::lang::ref::NotifyObjectEventListener* listener, int flags, AllocatedType type)
{
// ### @todo not implementable
/*
if (flags & ListObjectsRecursive)
{
int sf = flags & ~ListObjectsRecursive;
core_vector<RHeapFrame>::iterator it = allHeaps().begin();
core_vector<RHeapFrame>::iterator end = allHeaps().end();
while (it != end)
{
RHeapFrame tf = *it;
if (tf->listedAllocated(listener, sf, type) == false)
break;
++it;
}
}
else
{
topHeapFrame()->listedAllocated(listener, flags, type);
}*/
}
//static
void
ObjectHeap::lockHeap()
{
_heapAccessLock.lock();
}
//static
void
ObjectHeap::unlockHeap()
{
_heapAccessLock.unlock();
}
} // sys
} // lang
} // acdk |