home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
kaffe-0.5p4-src.tgz
/
tar.out
/
contrib
/
kaffe
/
kaffevm
/
gc-incremental.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
6KB
|
290 lines
/*
* gc-incremental.c
* The garbage collector.
*
* WORK IN PROGRESS - DO NOT USE !!
*
* Copyright (c) 1996 Systems Architecture Research Centre,
* City University, London, UK.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* Written by Tim Wilkinson <tim@sarc.city.ac.uk>, August 1996.
*/
#define MDBG(s) s
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>
#if defined(HAVE_MALLOC_H)
#include <malloc.h>
#endif
#include "gtypes.h"
#include "access.h"
#include "object.h"
#include "constants.h"
#include "classMethod.h"
#include "thread.h"
#include "gc.h"
extern thread* finalman;
extern thread* garbageman;
extern thread* liveThreads;
int gcpoolsize = DEFAULT_POOLSIZE;
static void* poolBase; /* Base of malloced pool */
static void* allocBase; /* Base of allocatable pool */
static void* allocPtr; /* Current point in allocatable pool */
static void* allocLimit; /* Limit of allocatable pool */
static uintp allocSize; /* Size of allocatable pool */
static mapEntry* mapBase; /* Base of modified map */
static int pgsize;
static freePool freelists[NR_FREELISTS];
static gcHead* greyHead;
static gcHead* greyTail;
static gcHead* rootList;
static gcHead dummyObject[1];
static void scanMem(void*, void*);
static void garbageCollect(void);
/*
* Initialise garbage system.
*/
void
initGc(void)
{
uint32 i;
/* Allocate the total GC pool */
poolBase = malloc(gcpoolsize);
assert(poolBase != 0);
/* Find the pagesize */
#if defined(HAVE_GETPAGESIZE)
pgsize = getpagesize();
#else
pgsize = 1024; /* A relatively sensible default */
#endif
/* Allocation will be made in units of 64 bytes (object's are
* at least 32 bytes anyhow). We will therefore allocate a
* map with a byte per 64 byte block. This is used so we can
* determine which objects have been modified during the mutator's
* execution and so help with later garbage collection.
*/
i = gcpoolsize / MAP_UNIT_SIZE;
i = (i + pgsize - 1) & -pgsize; /* Round up to pagesize */
mapBase = poolBase;
allocBase = poolBase + i;
allocLimit = poolBase + gcpoolsize;
allocPtr = allocBase;
allocSize = allocLimit - allocBase;
/* Initialise freelists */
for (i = 0; i < NR_FREELISTS; i++) {
freelists[i].first = 0;
freelists[i].size = MAP_UNIT_SIZE << i;
}
/* Add a dummy object to the grey list */
greyHead = dummyObject;
greyTail = dummyObject;
}
/*
* Primitive object allocation.
*/
void*
newObject(int sz, classes* class, int arraysz, bool root)
{
freePool* flist;
object* obj;
int tsz;
flist = freelists;
tsz = (sz + sizeof(object)) >> MAP_UNIT_SHIFT;
while (tsz != 0) {
tsz = tsz >> 1;
flist++;
}
/* 'flist' is now a pointer into the relevant freelist */
if (flist->first != 0) {
obj = (object*)flist->first;
flist->first = flist->first->next;
}
else {
obj = (object*)allocPtr;
allocPtr = allocPtr + flist->size;
if (allocPtr >= allocLimit) {
assert("Out of space" == 0);
}
}
/* Mark the beginning of the object */
ADDR2MAP(obj)->flags = MAP_ALLOC;
/* Fill in gc details */
obj->gc.colour = COLOUR_WHITE;
obj->gc.size = sz;
obj->gc.nextGrey = 0;
obj->gc.nextRoot = 0;
/* Fill in object details */
obj->size = arraysz;
obj->dtable = (class != 0 ? class->dtable : 0);
/* If object is a root, add it to the root list */
if (root) {
obj->gc.nextRoot = rootList;
rootList = &obj->gc;
}
{
static int _cnt = 0;
if (++_cnt % 100 == 0) {
garbageCollect();
}
}
return (obj);
}
/*
* Garbage collect objects.
*/
static
void
garbageCollect(void)
{
thread* tid;
gcHead* ref;
void* base;
/* Reset with a dummy object */
greyHead = dummyObject;
greyTail = dummyObject;
/* Grey the known root objects */
for (ref = rootList; ref != 0; ref = ref->nextRoot) {
if (IS_WHITEOBJECT(ref)) {
GREYOBJECT(ref);
MDBG( printf("Marking %x\n", ref); )
}
}
/* Scan each live thread, greying the thread objects and scanning
* the stacks.
*/
for (tid = liveThreads; tid != 0; tid = tid->PrivateInfo->nextlive) {
if (IS_WHITEOBJECT(tid)) {
GREYOBJECT(tid);
MDBG( printf("Marking %x\n", tid); )
}
scanMem(tid->PrivateInfo->restorePoint, tid->PrivateInfo->stackEnd);
}
/* Walk down the grey list, scanning each object for references to
* other objects (skipping the dummy object).
*/
for (ref = greyHead->nextGrey; ref != 0; ref = ref->nextGrey) {
base = (void*)(((object*)ref)+1);
ref->colour = COLOUR_BLACK;
scanMem(base, base + ref->size);
}
}
/*
* Scan an area of memory for valid object references.
*/
static
void
scanMem(void* from, void* to)
{
void** base;
for (base = (void**)from; (void*)base < to; base++) {
if (VALID_HEAPADDR(*base) && VALID_OBJECT(*base) && IS_WHITEOBJECT(*base)) {
GREYOBJECT(*base);
MDBG( printf("Marking %x\n", *base); )
}
}
}
/*
* Finaliser.
* Finalises any objects which have been garbage collected before
* deleting them.
*/
void
finaliserMan(void)
{
/* All threads start with interrupts disabled */
intsRestore();
lockMutex(&finalman->obj);
for (;;) {
waitCond(&finalman->obj, waitforever);
}
}
/*
* Garbage collector.
* Run the garbage collector.
*/
void
gcMan(void)
{
/* All threads start with interrupts disabled */
intsRestore();
lockMutex(&garbageman->obj);
for (;;) {
waitCond(&garbageman->obj, waitforever);
/* Run the garbage collector */
garbageCollect();
/* If there's garbage, finalise it */
if (finalman != 0) {
lockMutex(&finalman->obj);
signalCond(&finalman->obj);
unlockMutex(&finalman->obj);
}
}
}
/*
* Invoke the garbage collector (if we have one)
*/
void
invokeGarbageCollector(void)
{
if (garbageman != 0) {
lockMutex(&garbageman->obj);
signalCond(&garbageman->obj);
unlockMutex(&garbageman->obj);
}
}
/*
* Add an object to the garbage collection system.
*/
void
soft_addtogc(gcHead* obj)
{
assert(IS_WHITEOBJECT(obj));
GREYOBJECT(obj);
MDBG( printf("Adding mark for %x\n", obj); )
}