/* check-heap.c
*
* COPYRIGHT (c) 1994 by AT&T Bell Laboratories.
*/
#include "ml-base.h"
#include "card-map.h"
#include "heap.h"
#include "c-globals-tbl.h"
#ifndef CHECK_HEAP
# error CHECK_HEAP must be defined too
#endif
/* local routines */
PVT void CheckRecordArena (arena_t *ap);
PVT void CheckPairArena (arena_t *ap);
PVT void CheckStringArena (arena_t *ap);
PVT void CheckArrayArena (arena_t *ap, card_map_t *cm);
PVT int CheckPtr (ml_val_t *p, ml_val_t w, int srcGen, int srcKind, int dstKind);
PVT int ErrCount = 0;
/* CheckPtr dstKind values */
#define OBJC_NEWFLG (1 << OBJC_new)
#define OBJC_RECFLG (1 << OBJC_record)
#define OBJC_PAIRFLG (1 << OBJC_pair)
#define OBJC_STRFLG (1 << OBJC_string)
#define OBJC_ARRFLG (1 << OBJC_array)
#define OBJC_any \
(OBJC_NEWFLG|OBJC_RECFLG|OBJC_PAIRFLG|OBJC_STRFLG|OBJC_ARRFLG)
#define ERROR { \
if (++ErrCount > 100) { \
Die("CheckHeap: too many errors\n"); \
} \
}
/* CheckHeap:
*
* Check the heap for consistency after a garbage collection (or blast out).
*/
void CheckHeap (heap_t *heap, int maxSweptGen)
{
int i, j;
ErrCount = 0;
SayDebug ("Checking heap (%d generations) ...\n", maxSweptGen);
for (i = 0; i < maxSweptGen; i++) {
gen_t *g = heap->gen[i];
CheckRecordArena (g->arena[RECORD_INDX]);
CheckPairArena (g->arena[PAIR_INDX]);
CheckStringArena (g->arena[STRING_INDX]);
CheckArrayArena (g->arena[ARRAY_INDX], g->dirty);
}
SayDebug ("... done\n");
if (ErrCount > 0)
Die ("CheckHeap --- inconsistent heap\n");
} /* end of CheckHeap */
/* CheckRecordArena:
*
* Check the record arena.
*/
PVT void CheckRecordArena (arena_t *ap)
{
ml_val_t *p, *stop, desc, w;
int i, len;
int gen = EXTRACT_GEN(ap->id);
if (! isACTIVE(ap))
return;
SayDebug (" records [%d]: [%#x..%#x:%#x)\n",
gen, ap->tospBase, ap->nextw, ap->tospTop);
p = ap->tospBase;
stop = ap->nextw;
while (p < stop) {
desc = *p++;
if (! isDESC(desc)) {
ERROR;
SayDebug (
"** @%#x: expected descriptor, but found %#x in record arena\n",
p-1, desc);
return;
}
switch (GET_TAG(desc)) {
case DTAG_record:
len = GET_LEN(desc);
for (i = 0; i < len; i++, p++) {
w = *p;
if (isDESC(w)) {
ERROR;
SayDebug (
"** @%#x: unexpected descriptor %#x in slot %d of %d\n",
p, w, i, GET_LEN(desc));
return;
}
else if (isBOXED(w)) {
CheckPtr(p, w, gen, OBJC_record, OBJC_any);
}
}
break;
case DTAG_arr_hdr:
case DTAG_vec_hdr:
switch (GET_LEN(desc)) {
case SEQ_poly:
if (GET_TAG(desc) == DTAG_arr_hdr)
CheckPtr (p, *p, gen, OBJC_record, OBJC_ARRFLG);
else
CheckPtr (p, *p, gen, OBJC_record, OBJC_RECFLG|OBJC_PAIRFLG);
break;
case SEQ_word8:
case SEQ_word16:
case SEQ_word31:
case SEQ_word32:
case SEQ_real32:
case SEQ_real64:
CheckPtr (p, *p, gen, OBJC_record, OBJC_STRFLG);
break;
default:
ERROR;
SayDebug ("** @%#x: strange sequence kind %d in record arena\n",
p-1, GET_LEN(desc));
return;
}
if (! isUNBOXED(p[1])) {
ERROR;
SayDebug ("** @%#x: sequence header length field not an in (%#x)\n",
p+1, p[1]);
}
p += 2;
break;
default:
ERROR;
SayDebug ("** @%#x: strange tag (%#x) in record arena\n",
p-1, GET_TAG(desc));
return;
} /* end of switch */
}
} /* end of CheckRecordArena */
/* CheckPairArena:
*/
PVT void CheckPairArena (arena_t *ap)
{
ml_val_t *p, *stop, w;
int gen = EXTRACT_GEN(ap->id);
if (! isACTIVE(ap))
return;
SayDebug (" pairs [%d]: [%#x..%#x:%#x)\n",
gen, ap->tospBase, ap->nextw, ap->tospTop);
p = ap->tospBase + 2;
stop = ap->nextw;
while (p < stop) {
w = *p++;
if (isDESC(w)) {
ERROR;
SayDebug (
"** @%#x: unexpected descriptor %#x in pair arena\n",
p-1, w);
return;
}
else if (isBOXED(w)) {
CheckPtr(p, w, gen, OBJC_pair, OBJC_any);
}
}
} /* end of CheckPairArena */
/* CheckStringArena:
*
* Check a string arena for consistency.
*/
PVT void CheckStringArena (arena_t *ap)
{
ml_val_t *p, *stop, *prevDesc, desc, next;
int len;
int gen = EXTRACT_GEN(ap->id);
if (! isACTIVE(ap))
return;
SayDebug (" strings [%d]: [%#x..%#x:%#x)\n",
gen, ap->tospBase, ap->nextw, ap->tospTop);
p = ap->tospBase;
stop = ap->nextw;
prevDesc = NIL(ml_val_t *);
while (p < stop) {
desc = *p++;
if (isDESC(desc)) {
switch (GET_TAG(desc)) {
case DTAG_raw32:
case DTAG_raw64:
len = GET_LEN(desc);
break;
default:
ERROR;
SayDebug ("** @%#x: strange tag (%#x) in string arena\n",
p-1, GET_TAG(desc));
if (prevDesc != NIL(ml_val_t *))
SayDebug (" previous string started @ %#x\n", prevDesc);
return;
}
prevDesc = p-1;
p += len;
}
#ifdef ALIGN_REALDS
else if ((desc == 0) && (((Addr_t)p & WORD_SZB) != 0))
/* assume this is alignment padding */
continue;
#endif
else {
ERROR;
SayDebug (
"** @%#x: expected descriptor, but found %#x in string arena\n",
p-1, desc);
if (prevDesc != NIL(ml_val_t *))
SayDebug (" previous string started @ %#x\n", prevDesc);
return;
}
}
} /* end of CheckStringArena */
/* CheckArrayArena:
*/
PVT void CheckArrayArena (arena_t *ap, card_map_t *cm)
{
ml_val_t *p, *stop, desc, w;
int i, j, len;
int gen = EXTRACT_GEN(ap->id);
if (! isACTIVE(ap))
return;
SayDebug (" arrays [%d]: [%#x..%#x:%#x)\n",
gen, ap->tospBase, ap->nextw, ap->tospTop);
p = ap->tospBase;
stop = ap->nextw;
while (p < stop) {
desc = *p++;
if (! isDESC(desc)) {
ERROR;
SayDebug (
"** @%#x: expected descriptor, but found %#x in array arena\n",
p-1, desc);
return;
}
switch (GET_TAG(desc)) {
case DTAG_arr_data:
len = GET_LEN(desc);
break;
case DTAG_special:
len = 1;
break;
default:
ERROR;
SayDebug ("** @%#x: strange tag (%#x) in array arena\n",
p-1, GET_TAG(desc));
return;
} /* end of switch */
for (i = 0; i < len; i++, p++) {
w = *p;
if (isDESC(w)) {
ERROR;
SayDebug (
"** @%#x: unexpected descriptor %#x in array slot %d of %d\n",
p, w, i, GET_LEN(desc));
for (p -= (i+1), j = 0; j <= len; j++, p++) {
SayDebug (" %#x: %#10x\n", p, *p);
}
return;
}
else if (isBOXED(w)) {
CheckPtr(p, w, gen, OBJC_array, OBJC_any);
}
}
}
} /* end of CheckArrayArena */
/* CheckPtr:
*/
PVT int CheckPtr (ml_val_t *p, ml_val_t w, int srcGen, int srcKind, int dstKind)
{
aid_t aid = ADDR_TO_PAGEID(BIBOP, w);
int dstGen = EXTRACT_GEN(aid);
int objc = EXTRACT_OBJC(aid);
switch (objc) {
case OBJC_record:
case OBJC_pair:
case OBJC_string:
case OBJC_array:
if (!(dstKind & (1 << objc))) {
ERROR;
SayDebug (
"** @%#x: sequence data kind mismatch (expected %d, found %d)\n",
p, dstKind, objc);
}
if (dstGen < srcGen) {
if (srcKind != OBJC_array) {
ERROR;
SayDebug (
"** @%#x: reference to younger object @%#x (gen = %d)\n",
p, w, dstGen);
}
}
if ((objc != OBJC_pair) && (! isDESC(((ml_val_t *)w)[-1]))) {
ERROR;
SayDebug ("** @%#x: reference into object middle @#x\n", p, w);
}
break;
case OBJC_bigobj:
break;
case OBJC_new:
ERROR;
SayDebug ("** @%#x: unexpected new-space reference\n", p);
dstGen = MAX_NUM_GENS;
break;
default:
if (aid == AID_UNMAPPED) {
if (AddrToCSymbol(w) == NIL(const char *)) {
ERROR;
SayDebug (
"** @%#x: reference to unregistered external address %#x\n",
p, w);
}
dstGen = MAX_NUM_GENS;
}
else Die("bogus object class in BIBOP\n");
break;
} /* end of switch */
return dstGen;
} /* end of CheckPtr */
syntax highlighted by Code2HTML, v. 0.9.1