180 lines
3.8 KiB
C
180 lines
3.8 KiB
C
|
/*****************************************************************************
|
||
|
*
|
||
|
* gc.c
|
||
|
*
|
||
|
* The garbage-collector.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include "m4.h"
|
||
|
|
||
|
#ifndef Gc
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* WalkPv
|
||
|
*
|
||
|
* Mark an arbitrary object.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
void STDCALL
|
||
|
WalkPv(PVOID pv)
|
||
|
{
|
||
|
if (pv) {
|
||
|
PAR par = parPv(pv);
|
||
|
Assert(par->tm == g_tmNow - 1);
|
||
|
par->tm = g_tmNow;
|
||
|
AssertPar(par); /* This catches double-references */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* WalkPtok
|
||
|
*
|
||
|
* Walk a token. The token itself is not walked, but its contents are.
|
||
|
* (Because tokens are typically embedded inside other objects.)
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
void STDCALL
|
||
|
WalkPtok(PTOK ptok)
|
||
|
{
|
||
|
if (ptok) {
|
||
|
if (!fStaticPtok(ptok)) {
|
||
|
Assert(fHeapPtok(ptok));
|
||
|
WalkPv(ptchPtok(ptok));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* WalkPval
|
||
|
*
|
||
|
* Walk a value.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
void STDCALL
|
||
|
WalkPval(PVAL pval)
|
||
|
{
|
||
|
if (pval) {
|
||
|
WalkPv(pval);
|
||
|
WalkPtok(&pval->tok);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* WalkPmac
|
||
|
*
|
||
|
* Walk a macro.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
void STDCALL
|
||
|
WalkPmac(PMAC pmac)
|
||
|
{
|
||
|
if (pmac) {
|
||
|
PVAL pval;
|
||
|
WalkPv(pmac);
|
||
|
WalkPtok(&pmac->tokName);
|
||
|
for (pval = pmac->pval; pval; pval = pval->pvalPrev) {
|
||
|
WalkPval(pval);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* WalkPstm
|
||
|
*
|
||
|
* Walk a stream.
|
||
|
*
|
||
|
* The compiler knows how to optimize tail recursion.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
void STDCALL
|
||
|
WalkPstm(PSTM pstm)
|
||
|
{
|
||
|
if (pstm) {
|
||
|
WalkPv(pstm);
|
||
|
WalkPv(pstm->ptchMin);
|
||
|
WalkPv(pstm->ptchName);
|
||
|
WalkPstm(pstm->pstmNext);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* WalkPdiv
|
||
|
*
|
||
|
* Walk a diversion.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
void STDCALL
|
||
|
WalkPdiv(PDIV pdiv)
|
||
|
{
|
||
|
if (pdiv) {
|
||
|
WalkPv(pdiv);
|
||
|
WalkPv(pdiv->ptchMin);
|
||
|
WalkPv(pdiv->ptchName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Sweep
|
||
|
*
|
||
|
* Sweep through memory, looking for garbage.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
void STDCALL
|
||
|
Sweep(void)
|
||
|
{
|
||
|
PAR par;
|
||
|
for (par = parHead->parNext; par != parHead; par = par->parNext) {
|
||
|
Assert(par->tm == g_tmNow); /* Memory should have been walked! */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Gc
|
||
|
*
|
||
|
* The garbage collector is mark-and-sweep.
|
||
|
*
|
||
|
* Walk all the root objects, recursing into sub-objects, until everything
|
||
|
* is marked with the current (fake) timestamp. Then walk through the
|
||
|
* memory arenas. Anything not marked with the current timestamp is garbage.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
TM g_tmNow;
|
||
|
|
||
|
void STDCALL
|
||
|
Gc(void)
|
||
|
{
|
||
|
g_tmNow++;
|
||
|
if (mphashpmac) {
|
||
|
WalkPv(mphashpmac);
|
||
|
EachMacroOp(WalkPmac);
|
||
|
}
|
||
|
WalkPv(rgtokArgv);
|
||
|
WalkPv(rgcellEstack);
|
||
|
WalkPstm(g_pstmCur);
|
||
|
WalkPdiv(g_pdivArg);
|
||
|
WalkPdiv(g_pdivExp);
|
||
|
WalkPdiv(g_pdivOut);
|
||
|
WalkPdiv(g_pdivErr);
|
||
|
WalkPdiv(g_pdivNul);
|
||
|
Sweep();
|
||
|
}
|
||
|
|
||
|
#endif
|