blob: ed3da0a048126626d8c731f8a34e8249e328c722 [file] [log] [blame]
//===----------- gccollector.cc - Mvm Garbage Collector -------------------===//
//
// Mvm
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "MvmGC.h"
using namespace mvm;
GCAllocator *Collector::allocator = 0;
SpinLock Collector::_globalLock;
int Collector::status;
GCChunkNode *Collector::used_nodes;
GCChunkNode *Collector::unused_nodes;
unsigned int Collector::current_mark;
int Collector::_collect_freq_auto;
int Collector::_collect_freq_maybe;
int Collector::_since_last_collection;
bool Collector::_enable_auto;
bool Collector::_enable_maybe;
bool Collector::_enable_collection;
void Collector::do_collect() {
GCChunkNode *cur;
#ifdef SERVICE
mvm::Thread::get()->MyVM->_since_last_collection = _collect_freq_auto;
#else
_since_last_collection = _collect_freq_auto;
#endif
current_mark++;
unused_nodes->attrape(used_nodes);
mvm::Thread* th = mvm::Thread::get();
mvm::StackScanner* sc = th->MyVM->getScanner();
th->MyVM->rendezvous.startRV();
th->MyVM->startCollection();
th->MyVM->rendezvous.synchronize();
mvm::Thread* tcur = th;
// (1) Trace the VM.
th->MyVM->tracer();
// (2) Trace the threads.
do {
sc->scanStack(tcur);
tcur->tracer();
tcur = (mvm::Thread*)tcur->next();
} while (tcur != th);
// (3) Trace stack objects.
for(cur = used_nodes->next(); cur != used_nodes; cur = cur->next())
trace(cur);
// Go back to the previous node.
cur = cur->prev();
// (4) Trace the weak reference queue.
th->MyVM->scanWeakReferencesQueue();
// (5) Trace the soft reference queue.
th->MyVM->scanSoftReferencesQueue();
// (6) Trace the finalization queue.
th->MyVM->scanFinalizationQueue();
// (7) Trace the phantom reference queue.
th->MyVM->scanPhantomReferencesQueue();
// (8) Trace the new objects added by queues.
for(cur = cur->next(); cur != used_nodes; cur = cur->next())
trace(cur);
// Finalize.
GCChunkNode finalizable;
finalizable.attrape(unused_nodes);
// We have stopped collecting, go back to alloc state.
status = stat_alloc;
// Wake up all threads.
th->MyVM->endCollection();
th->MyVM->rendezvous.finishRV();
th->MyVM->wakeUpFinalizers();
th->MyVM->wakeUpEnqueue();
// Kill unreachable objects.
GCChunkNode *next = 0;
for(cur=finalizable.next(); cur!=&finalizable; cur=next) {
next = cur->next();
allocator->reject_chunk(cur);
}
}
void Collector::collect_unprotect() {
if(_enable_collection && (status == stat_alloc)) {
status = stat_collect;
do_collect();
}
}
void Collector::gcStats(size_t *_no, size_t *_nbb) {
register unsigned int n, tot;
register GCChunkNode *cur;
lock();
for(n=0, tot=0, cur=used_nodes->next(); cur!=used_nodes; cur=cur->next(), n++)
tot += cur->nbb();
unlock();
*_no = n;
*_nbb = tot;
}