git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@128 626c5289-ae23-0410-ae9c-e8d60b6d4f22
411 lines
10 KiB
C
411 lines
10 KiB
C
/* -----------------------------------------------------------------------------
|
|
* memory.c
|
|
*
|
|
* This file implements all of DOH's memory management including allocation
|
|
* of objects, checking of objects, and garbage collection.
|
|
*
|
|
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
|
|
*
|
|
* Copyright (C) 1999-2000. The University of Chicago
|
|
* See the file LICENSE for information on usage and redistribution.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static char cvsroot[] = "$Header$";
|
|
|
|
#include "dohint.h"
|
|
|
|
#ifndef DOH_POOL_SIZE
|
|
#define DOH_POOL_SIZE 128000
|
|
#endif
|
|
|
|
#ifndef DOH_MAX_FRAG
|
|
#define DOH_MAX_FRAG 1024
|
|
#endif
|
|
|
|
#ifndef DOH_MAX_SCOPES
|
|
#define DOH_MAX_SCOPES 256
|
|
#endif
|
|
|
|
static int _DohMemoryCurrent = 0;
|
|
static int _DohMemoryHigh = 0;
|
|
static int _PoolSize = DOH_POOL_SIZE;
|
|
|
|
DOH *DohNone = 0; /* The DOH None object */
|
|
|
|
typedef struct fragment {
|
|
char *ptr; /* Pointer to fragment */
|
|
int len; /* Length of fragment */
|
|
struct fragment *next; /* Next fragment */
|
|
} Fragment;
|
|
|
|
static Fragment *FreeFragments[DOH_MAX_FRAG];
|
|
|
|
typedef struct pool {
|
|
char *ptr; /* Start of pool */
|
|
int len; /* Length of pool */
|
|
int current; /* Current position for next allocation */
|
|
struct pool *next; /* Next pool */
|
|
} Pool;
|
|
|
|
static Pool *Pools = 0;
|
|
static int pools_initialized = 0;
|
|
static DohBase *scopes[DOH_MAX_SCOPES];
|
|
static int nscopes = 0;
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* CreatePool()
|
|
*
|
|
* Create a new memory pool
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
static Pool *
|
|
CreatePool(int size) {
|
|
Pool *p = 0;
|
|
char *c;
|
|
c = (char *) DohMalloc(size);
|
|
if (!c) return 0;
|
|
|
|
p = (Pool *) DohMalloc(sizeof(Pool));
|
|
p->ptr = c;
|
|
p->len = size;
|
|
p->current = 0;
|
|
p->next = 0;
|
|
return p;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* InitPools()
|
|
*
|
|
* Initialize the memory allocator
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
static void
|
|
InitPools() {
|
|
int i;
|
|
if (pools_initialized) return;
|
|
for (i = 0; i < DOH_MAX_FRAG; i++) {
|
|
FreeFragments[i] = 0;
|
|
}
|
|
Pools = CreatePool(_PoolSize); /* Create initial pool */
|
|
pools_initialized = 1;
|
|
for (i = 0; i < DOH_MAX_SCOPES; i++) {
|
|
scopes[i] = 0;
|
|
}
|
|
DohNewScope(); /* Initialize the scope system */
|
|
DohNone = NewVoid(0,0);
|
|
DohIntern(DohNone);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* DohCheck()
|
|
*
|
|
* Returns 1 if an arbitrary pointer is a DOH object. This determination
|
|
* is made according to the pointer value only.
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
int
|
|
DohCheck(DOH *ptr) {
|
|
Pool *p = Pools;
|
|
char *cptr = (char *) ptr;
|
|
while (p) {
|
|
if ((cptr >= p->ptr) && (cptr < p->ptr+p->current)) return 1;
|
|
p = p->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* DohObjFreeCheck()
|
|
*
|
|
* Checks to see if an object was already deleted. Useful when tracking
|
|
* down nasty double-free problems.
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
int
|
|
DohObjFreeCheck(DOH *ptr) {
|
|
int i;
|
|
Fragment *f;
|
|
char *cptr = (char *) ptr;
|
|
for (i = 0; i < DOH_MAX_FRAG; i++) {
|
|
f = FreeFragments[i];
|
|
while (f) {
|
|
if (f->ptr == cptr) return 1;
|
|
f = f->next;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* DohNewScope()
|
|
*
|
|
* Create a new scope in which objects will be placed. Returns a scope
|
|
* identifier.
|
|
* ---------------------------------------------------------------------- */
|
|
int
|
|
DohNewScope() {
|
|
assert(nscopes < DOH_MAX_SCOPES);
|
|
if (!pools_initialized) InitPools();
|
|
scopes[nscopes] = 0;
|
|
nscopes++;
|
|
return nscopes - 1;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* DohDelScope()
|
|
*
|
|
* Deletes a scope.
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
void
|
|
DohDelScope(int s) {
|
|
int ns;
|
|
DohBase *b, *b1;
|
|
ns = s;
|
|
assert((s >= 0) && (s < nscopes));
|
|
s = nscopes - 1;
|
|
while (s >= ns) {
|
|
b = scopes[s];
|
|
b1 = 0;
|
|
while (b) {
|
|
if (s <= b->scope) {
|
|
if (!(b->flags & DOH_FLAG_DELSCOPE)) {
|
|
Delete(b);
|
|
b->flags = b->flags | DOH_FLAG_DELSCOPE;
|
|
}
|
|
}
|
|
b1 = b;
|
|
b = (DohBase *) (b->nextptr);
|
|
}
|
|
if (ns > 0) { /* Add objects to highest non-deleted scope */
|
|
if (b1) {
|
|
b1->nextptr = (DOH *) scopes[ns-1];
|
|
scopes[ns-1] = (DohBase *) scopes[s];
|
|
}
|
|
}
|
|
scopes[s] = 0;
|
|
s--;
|
|
}
|
|
nscopes = ns;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* real_objfree()
|
|
*
|
|
* This is the function that actually frees an object. Invoked by the
|
|
* garbage collector.
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
static void
|
|
real_objfree(DOH *ptr) {
|
|
DohBase *b;
|
|
Fragment *f;
|
|
b = (DohBase *) ptr;
|
|
|
|
if (!b->objinfo) {
|
|
DohTrace(DOH_MEMORY,"DohObjFree. %x not properly defined. No objinfo structure.\n", ptr);
|
|
return; /* Improperly initialized object. leak some more */
|
|
}
|
|
f = (Fragment *) DohMalloc(sizeof(Fragment));
|
|
f->ptr = (char *) ptr;
|
|
f->len = (b->objinfo->objsize + 7) & ~0x07;
|
|
f->next = FreeFragments[f->len];
|
|
FreeFragments[f->len] = f;
|
|
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* DohGarbageCollect()
|
|
*
|
|
* This walks through all of the scopes and does garbage collection.
|
|
*
|
|
* 1. Objects with refcount <= 0 are released.
|
|
* 2. The scopes data structures are rebuilt and compacted.
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
void
|
|
DohGarbageCollect() {
|
|
int s;
|
|
DohBase *b, *b1;
|
|
int ndeleted = 1;
|
|
|
|
DohTrace(DOH_MEMORY,"Garbage collecting.\n");
|
|
while (ndeleted) {
|
|
ndeleted = 0;
|
|
s = nscopes - 1;
|
|
while (s >= 0) {
|
|
b = scopes[s];
|
|
b1 = 0;
|
|
while (b) {
|
|
if ((b->refcount <= 0)) {
|
|
if (b1) {
|
|
b1->nextptr = b->nextptr;
|
|
} else {
|
|
scopes[s] = b->nextptr;
|
|
}
|
|
if (!(b->flags & DOH_FLAG_INTERN)) {
|
|
assert(!(b->flags & DOH_FLAG_GC));
|
|
real_objfree(b); /* Release the object */
|
|
b->flags = b->flags | DOH_FLAG_GC;
|
|
}
|
|
ndeleted++;
|
|
} else {
|
|
b1 = b;
|
|
}
|
|
b = (DohBase *) b->nextptr;
|
|
}
|
|
s--;
|
|
}
|
|
}
|
|
DohTrace(DOH_MEMORY,"Done garbage collecting.\n");
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* DohObjMalloc()
|
|
*
|
|
* Allocate memory for a new object.
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
void *
|
|
DohObjMalloc(size_t size) {
|
|
Pool *p;
|
|
Fragment *f;
|
|
void *ptr = 0;
|
|
int garbage_collected = 0;
|
|
|
|
if (size > DOH_MAX_FRAG) return 0;
|
|
if (!pools_initialized) InitPools();
|
|
|
|
/* adjust the size for double word alignment */
|
|
size = (size + 7) & ~0x07;
|
|
|
|
retry:
|
|
p = Pools;
|
|
f = FreeFragments[size];
|
|
if (f) {
|
|
ptr = (void *) f->ptr;
|
|
FreeFragments[size] = f->next;
|
|
DohFree(f);
|
|
DohInit(ptr);
|
|
if (nscopes) {
|
|
((DohBase *) ptr)->scope = nscopes-1;
|
|
((DohBase *) ptr)->nextptr = scopes[nscopes-1];
|
|
scopes[nscopes-1] = (DohBase *) ptr;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
/* No free fragments. See if the pool is large enough */
|
|
if ((int) size < (p->len - p->current)) {
|
|
ptr = (void *) (p->ptr + p->current);
|
|
/* p->current = (p->current + size + 7) & ~0x3; */
|
|
p->current = p->current + size;
|
|
DohInit(ptr);
|
|
if (nscopes) {
|
|
((DohBase *) ptr)->scope = nscopes-1;
|
|
((DohBase *) ptr)->nextptr = scopes[nscopes-1];
|
|
scopes[nscopes-1] = (DohBase *) ptr;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
if (!garbage_collected) {
|
|
garbage_collected = 1;
|
|
DohGarbageCollect();
|
|
goto retry;
|
|
}
|
|
|
|
/* Pool is not large enough. Create a new pool */
|
|
if (p->len - p->current > 0) {
|
|
f = (Fragment *) DohMalloc(sizeof(Fragment));
|
|
f->ptr = (p->ptr + p->current);
|
|
f->len = (p->len - p->current);
|
|
f->next = FreeFragments[f->len];
|
|
p->current = p->len;
|
|
FreeFragments[f->len] = f;
|
|
}
|
|
|
|
p = CreatePool(_PoolSize);
|
|
p->next = Pools;
|
|
Pools = p;
|
|
return DohObjMalloc(size);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* DohObjFree()
|
|
*
|
|
* Frees a DOH object. Doesn't do much with GC.
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
void
|
|
DohObjFree(DOH *ptr) {
|
|
DohBase *b;
|
|
if (!DohCheck(ptr)) {
|
|
DohTrace(DOH_MEMORY,"DohObjFree. %x not a DOH object!\n", ptr);
|
|
return; /* Oh well. Guess we're leaky */
|
|
}
|
|
b = (DohBase *) ptr;
|
|
if (!b->objinfo) {
|
|
DohTrace(DOH_MEMORY,"DohObjFree. %x not properly defined. No objinfo structure.\n", ptr);
|
|
return; /* Improperly initialized object. leak some more */
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* DohMalloc()
|
|
*
|
|
* Wrapper around malloc() function. Records memory usage.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void *
|
|
DohMalloc(size_t nbytes) {
|
|
return (void *) malloc(nbytes);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* DohRealloc()
|
|
*
|
|
* Wrapper around realloc() function.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void *
|
|
DohRealloc(void *ptr, size_t newsize) {
|
|
return (void *) realloc(ptr,newsize);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* DohFree()
|
|
*
|
|
* Wrapper around free() function.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void
|
|
DohFree(void *ptr) {
|
|
free(ptr);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* DohPoolSize()
|
|
*
|
|
* Change the size of the memory pools used by DOH
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int
|
|
DohPoolSize(int poolsize) {
|
|
int ps;
|
|
ps = _PoolSize;
|
|
if (poolsize > 0) {
|
|
_PoolSize = poolsize;
|
|
}
|
|
return ps;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|