/* call-gc.c
*
* COPYRIGHT (c) 1993 by AT&T Bell Laboratories.
*
* The main interface between the GC and the rest of the run-time system.
* These are the routines used to invoke the GC.
*/
#ifdef PAUSE_STATS /* GC pause statistics are UNIX dependent */
# include "ml-unixdep.h"
#endif
#include <stdarg.h>
#include "ml-base.h"
#include "ml-limits.h"
#include "memory.h"
#include "ml-state.h"
#include "ml-values.h"
#include "ml-objects.h"
#include "cntr.h"
#include "heap.h"
#include "heap-monitor.h"
#include "ml-globals.h"
#include "ml-timer.h"
#include "gc-stats.h"
#include "vproc-state.h"
#include "profile.h"
#ifdef C_CALLS
/* This is a list of pointers into the C heap locations that hold
* pointers to ML functions. This list is not part of any ML data
* structure(s). (also see gc/major-gc.c and c-libs/c-calls/c-calls-fns.c)
*/
extern ml_val_t CInterfaceRootList;
#endif
/* InvokeGC:
*
* Invoke a garbage collection. A garbage collection always involves
* collecting the allocation space. In addition, if level is greater than
* 0, or if the first generation is full after the minor collection, then
* a major collection of one or more generations is performed (at least
* level generations are collected).
*/
void InvokeGC (ml_state_t *msp, int level)
{
ml_val_t *roots[NUM_GC_ROOTS]; /* registers and globals */
ml_val_t **rootsPtr = roots;
heap_t *heap;
int i;
#ifdef MP_SUPPORT
int nProcs;
#endif
ASSIGN(ProfCurrent, PROF_MINOR_GC);
#ifdef MP_SUPPORT
#ifdef MP_DEBUG
SayDebug ("igc %d\n", msp->ml_mpSelf);
#endif
if ((nProcs = MP_StartCollect (msp)) == 0) {
/* a waiting proc */
ASSIGN(ProfCurrent, PROF_RUNTIME);
return;
}
#endif
START_GC_PAUSE(msp->ml_heap);
#ifdef C_CALLS
*rootsPtr++ = &CInterfaceRootList;
#endif
#ifdef MP_SUPPORT
/* get extra roots from procs that entered through InvokeGCWithRoots */
for (i = 0; mpExtraRoots[i] != NIL(ml_val_t *); i++)
*rootsPtr++ = mpExtraRoots[i];
#endif
/* Gather the roots */
for (i = 0; i < NumCRoots; i++)
*rootsPtr++ = CRoots[i];
#ifdef MP_SUPPORT
{
vproc_state_t *vsp;
ml_state_t *msp;
int j;
for (j = 0; j < MAX_NUM_PROCS; j++) {
vsp = VProc[j];
msp = vsp->vp_state;
#ifdef MP_DEBUG
SayDebug ("msp[%d] alloc/limit was %x/%x\n",
j, msp->ml_allocPtr, msp->ml_limitPtr);
#endif
if (vsp->vp_mpState == MP_PROC_RUNNING) {
*rootsPtr++ = &(msp->ml_arg);
*rootsPtr++ = &(msp->ml_cont);
*rootsPtr++ = &(msp->ml_closure);
*rootsPtr++ = &(msp->ml_exnCont);
*rootsPtr++ = &(msp->ml_varReg);
*rootsPtr++ = &(msp->ml_calleeSave[0]);
*rootsPtr++ = &(msp->ml_calleeSave[1]);
*rootsPtr++ = &(msp->ml_calleeSave[2]);
}
} /* for */
}
#else /* !MP_SUPPORT */
*rootsPtr++ = &(msp->ml_linkReg);
*rootsPtr++ = &(msp->ml_arg);
*rootsPtr++ = &(msp->ml_cont);
*rootsPtr++ = &(msp->ml_closure);
*rootsPtr++ = &(msp->ml_exnCont);
*rootsPtr++ = &(msp->ml_varReg);
*rootsPtr++ = &(msp->ml_calleeSave[0]);
*rootsPtr++ = &(msp->ml_calleeSave[1]);
*rootsPtr++ = &(msp->ml_calleeSave[2]);
#endif /* MP_SUPPORT */
*rootsPtr = NIL(ml_val_t *);
MinorGC (msp, roots);
heap = msp->ml_heap;
/* Check for major GC */
if (level == 0) {
gen_t *gen1 = heap->gen[0];
Word_t sz = msp->ml_allocArenaSzB;
for (i = 0; i < NUM_ARENAS; i++) {
arena_t *arena = gen1->arena[i];
if (isACTIVE(arena) && (AVAIL_SPACE(arena) < sz)) {
level = 1;
break;
}
}
}
if (level > 0) {
#ifdef MP_SUPPORT
vproc_state_t *vsp;
ml_state_t *msp;
for (i = 0; i < MAX_NUM_PROCS; i++) {
vsp = VProc[i];
msp = vsp->vp_state;
if (vsp->vp_mpState == MP_PROC_RUNNING)
*rootsPtr++ = &(msp->ml_linkReg);
}
#else
ASSIGN(ProfCurrent, PROF_MAJOR_GC);
#endif
*rootsPtr = NIL(ml_val_t *);
MajorGC (msp, roots, level);
}
else {
HeapMon_UpdateHeap (heap, 1);
}
/* reset the allocation space */
#ifdef MP_SUPPORT
MP_FinishCollect (msp, nProcs);
#else
msp->ml_allocPtr = heap->allocBase;
#ifdef SOFT_POLL
ResetPollLimit (msp);
#else
msp->ml_limitPtr = HEAP_LIMIT(heap);
#endif
#endif
STOP_GC_PAUSE();
ASSIGN(ProfCurrent, PROF_RUNTIME);
} /* end of InvokeGC */
/* InvokeGCWithRoots:
*
* Invoke a garbage collection with possible additional roots. The list of
* additional roots should be NIL terminated. A garbage collection always
* involves collecting the allocation space. In addition, if level is greater
* than 0, or if the first generation is full after the minor collection, then
* a major collection of one or more generations is performed (at least level
* generations are collected).
*
* NOTE: the MP version of this may be broken, since if a processor calls this
* but isn't the collecting process, then the extra roots are lost.
*/
void InvokeGCWithRoots (ml_state_t *msp, int level, ...)
{
ml_val_t *roots[NUM_GC_ROOTS+NUM_EXTRA_ROOTS]; /* registers and globals */
ml_val_t **rootsPtr = roots, *p;
heap_t *heap;
int i;
va_list ap;
#ifdef MP_SUPPORT
int nProcs;
#endif
ASSIGN(ProfCurrent, PROF_MINOR_GC);
#ifdef MP_SUPPORT
#ifdef MP_DEBUG
SayDebug ("igcwr %d\n", msp->ml_mpSelf);
#endif
va_start (ap, level);
nProcs = MP_StartCollectWithRoots (msp, ap);
va_end(ap);
if (nProcs == 0)
ASSIGN(ProfCurrent, PROF_RUNTIME);
return; /* a waiting proc */
#endif
START_GC_PAUSE(msp->ml_heap);
#ifdef C_CALLS
*rootsPtr++ = &CInterfaceRootList;
#endif
#ifdef MP_SUPPORT
/* get extra roots from procs that entered through InvokeGCWithRoots.
* Our extra roots were placed in mpExtraRoots by MP_StartCollectWithRoots.
*/
for (i = 0; mpExtraRoots[i] != NIL(ml_val_t *); i++)
*rootsPtr++ = mpExtraRoots[i];
#else
/* record extra roots from param list */
va_start (ap, level);
while ((p = va_arg(ap, ml_val_t *)) != NIL(ml_val_t *)) {
*rootsPtr++ = p;
}
va_end(ap);
#endif /* MP_SUPPORT */
/* Gather the roots */
for (i = 0; i < NumCRoots; i++)
*rootsPtr++ = CRoots[i];
#ifdef MP_SUPPORT
{
ml_state_t *msp;
vproc_state_t *vsp;
int j;
for (j = 0; j < MAX_NUM_PROCS; j++) {
vsp = VProc[j];
msp = vsp->vp_state;
#ifdef MP_DEBUG
SayDebug ("msp[%d] alloc/limit was %x/%x\n",
j, msp->ml_allocPtr, msp->ml_limitPtr);
#endif
if (vsp->vp_mpState == MP_PROC_RUNNING) {
*rootsPtr++ = &(msp->ml_arg);
*rootsPtr++ = &(msp->ml_cont);
*rootsPtr++ = &(msp->ml_closure);
*rootsPtr++ = &(msp->ml_exnCont);
*rootsPtr++ = &(msp->ml_varReg);
*rootsPtr++ = &(msp->ml_calleeSave[0]);
*rootsPtr++ = &(msp->ml_calleeSave[1]);
*rootsPtr++ = &(msp->ml_calleeSave[2]);
}
} /* for */
}
#else /* !MP_SUPPORT */
*rootsPtr++ = &(msp->ml_arg);
*rootsPtr++ = &(msp->ml_cont);
*rootsPtr++ = &(msp->ml_closure);
*rootsPtr++ = &(msp->ml_exnCont);
*rootsPtr++ = &(msp->ml_varReg);
*rootsPtr++ = &(msp->ml_calleeSave[0]);
*rootsPtr++ = &(msp->ml_calleeSave[1]);
*rootsPtr++ = &(msp->ml_calleeSave[2]);
#endif /* MP_SUPPORT */
*rootsPtr = NIL(ml_val_t *);
MinorGC (msp, roots);
heap = msp->ml_heap;
/* Check for major GC */
if (level == 0) {
gen_t *gen1 = heap->gen[0];
Word_t sz = msp->ml_allocArenaSzB;
for (i = 0; i < NUM_ARENAS; i++) {
arena_t *arena = gen1->arena[i];
if (isACTIVE(arena) && (AVAIL_SPACE(arena) < sz)) {
level = 1;
break;
}
}
}
if (level > 0) {
#ifdef MP_SUPPORT
vproc_state_t *vsp;
for (i = 0; i < MAX_NUM_PROCS; i++) {
vsp = VProc[i];
if (vsp->vp_mpState == MP_PROC_RUNNING)
*rootsPtr++ = &(vsp->vp_state->ml_linkReg);
}
#else
ASSIGN(ProfCurrent, PROF_MAJOR_GC);
*rootsPtr++ = &(msp->ml_linkReg);
*rootsPtr++ = &(msp->ml_pc);
#endif
*rootsPtr = NIL(ml_val_t *);
MajorGC (msp, roots, level);
}
else {
HeapMon_UpdateHeap (heap, 1);
}
/* reset the allocation space */
#ifdef MP_SUPPORT
MP_FinishCollect (msp, nProcs);
#else
msp->ml_allocPtr = heap->allocBase;
#ifdef SOFT_POLL
ResetPollLimit (msp);
#else
msp->ml_limitPtr = HEAP_LIMIT(heap);
#endif
#endif
STOP_GC_PAUSE();
ASSIGN(ProfCurrent, PROF_RUNTIME);
} /* end of InvokeGCWithRoots */
/* NeedGC:
*
* Check to see if a GC is required, or if there is enough heap space for
* nbytes worth of allocation. Return TRUE, if GC is required, FALSE
* otherwise.
*/
bool_t NeedGC (ml_state_t *msp, Word_t nbytes)
{
#if (defined(MP_SUPPORT) && defined(COMMENT_MP_GCPOLL))
if ((((Addr_t)(msp->ml_allocPtr)+nbytes) >= (Addr_t)(msp->ml_limitPtr))
|| (INT_MLtoC(PollEvent) != 0))
#elif defined(MP_SUPPORT)
if (((Addr_t)(msp->ml_allocPtr)+nbytes) >= (Addr_t)(msp->ml_limitPtr))
#else
if (((Addr_t)(msp->ml_allocPtr)+nbytes) >= (Addr_t)HEAP_LIMIT(msp->ml_heap))
#endif
return TRUE;
else
return FALSE;
} /* end of NeedGC */
#ifdef SOFT_POLL
/* ResetPollLimit:
*
* Reset the limit pointer according to the current polling frequency.
*/
void ResetPollLimit (ml_state_t *msp)
{
int pollFreq = INT_MLtoC(DEREF(PollFreq));
heap_t *heap = msp->ml_heap;
/* assumes ml_allocPtr has been reset */
msp->ml_realLimit = HEAP_LIMIT(heap);
if (pollFreq > 0) {
msp->ml_limitPtr = heap->allocBase + pollFreq*POLL_GRAIN_CPSI;
msp->ml_limitPtr = (msp->ml_limitPtr > msp->ml_realLimit)
? msp->ml_realLimit
: msp->ml_limitPtr;
}
else
msp->ml_limitPtr = msp->ml_realLimit;
} /* end ResetPollLimit */
#endif /* SOFT_POLL */
syntax highlighted by Code2HTML, v. 0.9.1