mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-16 08:10:43 -08:00
New unit
new Copied from Perforce Change: 18774 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
381f6a25a8
commit
09dbd2e3ae
2 changed files with 689 additions and 0 deletions
563
mps/qa/test/testlib/rankfmt.c
Normal file
563
mps/qa/test/testlib/rankfmt.c
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
/* rankfmt.c
|
||||
See comments in header file for usage.
|
||||
*/
|
||||
|
||||
#include "mps.h"
|
||||
#include "testlib.h"
|
||||
#include "rankfmt.h"
|
||||
#include <string.h>
|
||||
|
||||
/* some options on the format are controlled by global
|
||||
variables. Of course for efficiency we'd do it in the
|
||||
pre-processor, but that would require recompilation...
|
||||
*/
|
||||
|
||||
int formatcomments=0;
|
||||
int checkcomments=0;
|
||||
int countcomments=1;
|
||||
int alloccomments=0;
|
||||
int fixcomments=0;
|
||||
int deathcomments=0;
|
||||
int skipcomments=0;
|
||||
int splurgeassoc=0; /* write madly to associated objects */
|
||||
|
||||
long int nextid=0x1000000;
|
||||
|
||||
long int checkobjcount=0;
|
||||
|
||||
mps_addr_t exfmt_root=NULL;
|
||||
|
||||
int counters[PAD_COUNT+1] = {0};
|
||||
int prevcounters[PAD_COUNT+1] = {0};
|
||||
int maxcounters[PAD_COUNT+1] = {0};
|
||||
|
||||
long int maxcopy = 0;
|
||||
int freeze=0;
|
||||
|
||||
/* The AWL pool makes certain assumptions about the object format,
|
||||
some necessary and some unnecessary but useful for detecting problems
|
||||
when using fmtdy. We have to ensure that:
|
||||
|
||||
Each objects begins with a pointer to a wrapper. To tag objects,
|
||||
use non-zero values for the low bits.
|
||||
The second word in each object is a pointer to the associated object,
|
||||
usual rules for references apply.
|
||||
|
||||
The wrapper begins with a wrapper-wrapper pointer, and the third word
|
||||
of the wrapper object has bit 0 set and bit 1 clear and at least one higher
|
||||
bit also set.
|
||||
|
||||
The wrapper-wrapper's first word points to itself.
|
||||
|
||||
Here I make the wrapper-wrapper equal to the wrapper for all objects,
|
||||
and use the same wrapper for all objects.
|
||||
|
||||
The other pools don't care about the wrapper, of course.
|
||||
*/
|
||||
|
||||
struct wrapper {
|
||||
struct wrapper *ww;
|
||||
mps_word_t tag;
|
||||
mps_word_t fixedlen;
|
||||
};
|
||||
|
||||
struct wrapper wrapobj = {
|
||||
&wrapobj,
|
||||
0x36ABBE6,
|
||||
0x5
|
||||
};
|
||||
|
||||
mycell *wrapper = (mycell *) &wrapobj;
|
||||
|
||||
#define INCCOUNT(c) do {if(!freeze) counters[c]+=1;} while (0)
|
||||
#define INCCOUNTIF(f, c) do {if(f) INCCOUNT(c);} while (0)
|
||||
|
||||
/* a cell can be one of four things, depending on its type:
|
||||
MCpad - a pad item
|
||||
MCheart - a broken heart, aka forwarding object
|
||||
MCdata - a real object
|
||||
*/
|
||||
|
||||
/* the scanning function doesn't try to fix null refs
|
||||
*/
|
||||
|
||||
static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit);
|
||||
static mps_addr_t myskip(mps_addr_t object);
|
||||
static void myfwd(mps_addr_t object, mps_addr_t to);
|
||||
static mps_addr_t myisfwd(mps_addr_t object);
|
||||
static void mycopy(mps_addr_t object, mps_addr_t to);
|
||||
static void mypad(mps_addr_t base, size_t size);
|
||||
|
||||
struct mps_fmt_A_s fmtA =
|
||||
{
|
||||
MPS_PF_ALIGN,
|
||||
&myscan,
|
||||
&myskip,
|
||||
&mycopy,
|
||||
&myfwd,
|
||||
&myisfwd,
|
||||
&mypad
|
||||
};
|
||||
|
||||
/* in the following, size is the number of refs you want
|
||||
the allocated object to have
|
||||
*/
|
||||
|
||||
mycell *allocdumb(mps_ap_t ap, size_t size, mps_rank_t rank)
|
||||
{
|
||||
mycell *q;
|
||||
size_t bytes;
|
||||
size_t alignment;
|
||||
|
||||
bytes = offsetof(struct data, ref) + size;
|
||||
|
||||
alignment = MPS_PF_ALIGN; /* needed to make it as wide as size_t */
|
||||
|
||||
/* twiddle the value of size to make it aligned */
|
||||
bytes = (bytes+alignment-1) & ~(alignment-1);
|
||||
|
||||
do
|
||||
{
|
||||
die(mps_reserve(&exfmt_root, ap, bytes), "Reserve: ");
|
||||
INCCOUNT(RESERVE_COUNT);
|
||||
q=exfmt_root;
|
||||
q->data.tag = (mps_word_t) wrapper;
|
||||
q->data.assoc = NULL;
|
||||
q->data.id = nextid;
|
||||
q->data.copycount = 0;
|
||||
q->data.numrefs = 0;
|
||||
q->data.checkedflag = 0;
|
||||
q->data.rank = rank;
|
||||
q->data.size = bytes;
|
||||
}
|
||||
while (!mps_commit(ap, exfmt_root, bytes));
|
||||
INCCOUNT(ALLOC_COUNT);
|
||||
commentif(alloccomments, "allocated id %li at %p.", nextid, q);
|
||||
nextid += 1;
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
mycell *allocone(mps_ap_t ap, int size, mps_rank_t rank)
|
||||
{
|
||||
mycell *q;
|
||||
int i;
|
||||
size_t bytes;
|
||||
size_t alignment;
|
||||
|
||||
bytes = offsetof(struct data, ref) + size*sizeof(struct refitem);
|
||||
|
||||
alignment = MPS_PF_ALIGN; /* needed to make it as wide as size_t */
|
||||
|
||||
/* twiddle the value of size to make it aligned */
|
||||
bytes = (bytes+alignment-1) & ~(alignment-1);
|
||||
|
||||
do
|
||||
{
|
||||
die(mps_reserve(&exfmt_root, ap, bytes), "Reserve: ");
|
||||
INCCOUNT(RESERVE_COUNT);
|
||||
q=exfmt_root;
|
||||
q->data.tag = MCdata + (mps_word_t) wrapper;
|
||||
q->data.assoc = NULL;
|
||||
q->data.id = nextid;
|
||||
q->data.copycount = 0;
|
||||
q->data.numrefs = size;
|
||||
q->data.checkedflag = 0;
|
||||
q->data.rank = rank;
|
||||
q->data.size = bytes;
|
||||
|
||||
for(i=0; i<size; i+=1)
|
||||
{
|
||||
q->data.ref[i].addr = NULL;
|
||||
q->data.ref[i].id = 0;
|
||||
}
|
||||
}
|
||||
while (!mps_commit(ap, exfmt_root, bytes));
|
||||
INCCOUNT(ALLOC_COUNT);
|
||||
commentif(alloccomments, "allocated id %li at %p.", nextid, q);
|
||||
nextid += 1;
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
|
||||
{
|
||||
int i;
|
||||
|
||||
INCCOUNT(SCANCALL_COUNT);
|
||||
MPS_SCAN_BEGIN(ss)
|
||||
{
|
||||
while (base < limit)
|
||||
{
|
||||
mycell *obj = base;
|
||||
mps_res_t res;
|
||||
mps_addr_t p, q;
|
||||
mps_rank_t rank;
|
||||
|
||||
switch (obj->tag & 0x3)
|
||||
{
|
||||
case MCpad:
|
||||
INCCOUNT(SCANPAD_COUNT);
|
||||
base = (mps_addr_t) (obj->pad.tag &~ (mps_word_t) 3);
|
||||
break;
|
||||
case MCdata:
|
||||
/* actual scanning is done in here */
|
||||
asserts(obj->tag == MCdata + (mps_word_t) wrapper, "scan on bad object");
|
||||
asserts(obj->data.id != MCerrorid, "scan on error object");
|
||||
rank = obj->data.rank;
|
||||
INCCOUNT(SCANOBJ_COUNT);
|
||||
commentif(formatcomments, "scan %li at %p.", obj->data.id, base);
|
||||
|
||||
/* make sure to fix the assoc pointer first */
|
||||
p = obj->data.assoc;
|
||||
if (p != NULL) {
|
||||
commentif(fixcomments, "fix %li[assoc]", obj->data.id);
|
||||
q = p;
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
if (res != MPS_RES_OK) return res;
|
||||
if (p == NULL) {
|
||||
asserts(rank == MPS_RANK_WEAK,
|
||||
"non-weak reference fixed to NULL at %p[assoc]", obj);
|
||||
commentif(deathcomments, "fixed %p[assoc] to NULL", obj->data.id);
|
||||
INCCOUNT(DYING_REFERENCE_COUNT);
|
||||
} else if (p != q) {
|
||||
asserts(rank != MPS_RANK_AMBIG,
|
||||
"ambiguous reference changed by fix at %p[assoc]", obj);
|
||||
}
|
||||
obj->data.assoc = p;
|
||||
}
|
||||
|
||||
for (i=0; i<(obj->data.numrefs); i++)
|
||||
{
|
||||
p = obj->data.ref[i].addr;
|
||||
if (p != NULL)
|
||||
{
|
||||
/* copy ref to p for fixing, to avoid a pun (although
|
||||
the pun would probably work fine almost everywhere)
|
||||
*/
|
||||
commentif(fixcomments, "fix %li[%i] -> %li",
|
||||
obj->data.id, i, obj->data.ref[i].id);
|
||||
q = p;
|
||||
res = MPS_FIX(ss, (mps_addr_t *) &p);
|
||||
if (p == NULL) {
|
||||
asserts(rank == MPS_RANK_WEAK,
|
||||
"non-weak reference fixed to NULL at %p[i]", obj);
|
||||
commentif(deathcomments, "fixed %li[%i] to NULL", obj->data.id, i);
|
||||
INCCOUNT(DYING_REFERENCE_COUNT);
|
||||
} else if (p != q) {
|
||||
asserts(rank != MPS_RANK_AMBIG,
|
||||
"ambiguous reference changed by fix at %p[i]", obj);
|
||||
}
|
||||
if (res != MPS_RES_OK) return res;
|
||||
obj->data.ref[i].addr = p;
|
||||
}
|
||||
}
|
||||
base = (mps_addr_t) ((char *) obj + (obj->data.size));
|
||||
break;
|
||||
case MCheart:
|
||||
INCCOUNT(SCANHEART_COUNT);
|
||||
base = (mps_addr_t) ((char *) obj + (obj->heart.size));
|
||||
break;
|
||||
default:
|
||||
asserts(0, "scan: bizarre obj tag at %p.", obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
MPS_SCAN_END(ss);
|
||||
return MPS_RES_OK;
|
||||
}
|
||||
|
||||
static mps_addr_t myskip(mps_addr_t object)
|
||||
{
|
||||
mycell *obj = object;
|
||||
|
||||
commentif(skipcomments, "skip %p.", object);
|
||||
INCCOUNT(SKIP_COUNT);
|
||||
switch(obj->tag & 0x3)
|
||||
{
|
||||
case MCpad:
|
||||
return (mps_addr_t) (obj->pad.tag &~ (mps_word_t) 0x3);
|
||||
case MCheart:
|
||||
return (mps_addr_t) ((char *) obj + (obj->heart.size));
|
||||
case MCdata:
|
||||
asserts(obj->tag == MCdata + (mps_word_t) wrapper,
|
||||
"skip on bad obj at %p.", obj);
|
||||
return (mps_addr_t) ((char *) obj + (obj->data.size));
|
||||
default:
|
||||
asserts(0, "skip: bizarre obj tag at %p.", obj);
|
||||
return 0; /* not reached */
|
||||
}
|
||||
}
|
||||
|
||||
static void mycopy(mps_addr_t object, mps_addr_t to)
|
||||
{
|
||||
mycell *boj = object;
|
||||
mycell *toj = to;
|
||||
|
||||
asserts(boj->tag == MCdata + (mps_word_t) wrapper,
|
||||
"copy: non-data object");
|
||||
|
||||
INCCOUNT(COPY_COUNT);
|
||||
commentif(formatcomments, "copy: %li: %p -> %p\n",
|
||||
boj->data.id, object, to);
|
||||
|
||||
/* this line would be bad, because the objects might overlap,
|
||||
and then C doesn't guarantee to do the right thing!
|
||||
|
||||
*toj = *boj;
|
||||
*/
|
||||
|
||||
memmove(to, object, boj->data.size);
|
||||
if (!freeze)
|
||||
{
|
||||
toj->data.copycount = (toj->data.copycount)+1;
|
||||
if (toj->data.copycount > maxcopy) maxcopy = toj->data.copycount;
|
||||
}
|
||||
}
|
||||
|
||||
/* pad stores not its size but a pointer to the next object,
|
||||
because we know we'll never be asked to copy it
|
||||
*/
|
||||
|
||||
static void mypad(mps_addr_t base, size_t size)
|
||||
{
|
||||
mycell *obj = base;
|
||||
|
||||
asserts(size >= MPS_PF_ALIGN, "pad: size too small.");
|
||||
|
||||
INCCOUNT(PAD_COUNT);
|
||||
obj->pad.tag = MCpad + (mps_word_t) ((char *) base + size);
|
||||
}
|
||||
|
||||
static mps_addr_t myisfwd(mps_addr_t object)
|
||||
{
|
||||
mycell *obj = object;
|
||||
|
||||
INCCOUNT(ISFWD_COUNT);
|
||||
if ((obj->tag & 3) != MCheart)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return obj->heart.obj;
|
||||
}
|
||||
}
|
||||
|
||||
static void myfwd(mps_addr_t object, mps_addr_t to)
|
||||
{
|
||||
mycell *obj = object;
|
||||
size_t size;
|
||||
|
||||
asserts(((obj->tag & 3) == MCdata) || ((obj->tag & 3) == MCheart),
|
||||
"fwd: unexpected object tag at %p.", obj);
|
||||
INCCOUNT(FWD_COUNT);
|
||||
|
||||
if ((obj->tag & 3) == MCdata)
|
||||
{
|
||||
asserts(obj->tag == MCdata + (mps_word_t) wrapper,
|
||||
"fwd: bad obj at %p.", obj);
|
||||
size = obj->data.size;
|
||||
}
|
||||
else /* obj->tag == MCheart */
|
||||
{
|
||||
size = obj->heart.size;
|
||||
}
|
||||
obj->data.tag = MCheart;
|
||||
obj->heart.obj = to;
|
||||
obj->heart.size = size;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
Access methods for mycell objects
|
||||
*/
|
||||
|
||||
/* set the nth reference of obj to to (n from 0 to size-1) */
|
||||
|
||||
void setref(mycell *obj, int n, mycell *to)
|
||||
{
|
||||
asserts(obj->tag == MCdata + (mps_word_t) wrapper,
|
||||
"setref: from non-data object at %p", obj);
|
||||
asserts((to==NULL)||((to->tag & 3) == MCdata),
|
||||
"setref: to non-data object at %p", to);
|
||||
asserts(obj->data.numrefs > n, "setref: access beyond object size.");
|
||||
|
||||
obj->data.ref[n].addr = to;
|
||||
obj->data.ref[n].id = (to==NULL ? 0 : to->data.id);
|
||||
}
|
||||
|
||||
mycell *getref(mycell *obj, int n)
|
||||
{
|
||||
asserts(obj->tag == MCdata + (mps_word_t) wrapper,
|
||||
"getref: from non-data object.");
|
||||
asserts(obj->data.numrefs > n, "getref: access beyond object size.");
|
||||
return obj->data.ref[n].addr;
|
||||
}
|
||||
|
||||
mps_addr_t getdata(mycell *obj)
|
||||
{
|
||||
return (mps_addr_t) &(obj->data.ref[0]);
|
||||
}
|
||||
|
||||
long int getid(mycell *obj)
|
||||
{
|
||||
asserts(obj->tag == MCdata + (mps_word_t) wrapper,
|
||||
"getid: non-data object.");
|
||||
return obj->data.id;
|
||||
}
|
||||
|
||||
long int getcopycount(mycell *obj)
|
||||
{
|
||||
asserts(obj->tag == MCdata + (mps_word_t) wrapper,
|
||||
"getcopycount: non-data object.");
|
||||
return obj->data.copycount;
|
||||
}
|
||||
|
||||
long int getsize(mycell *obj)
|
||||
{
|
||||
asserts(obj->tag == MCdata + (mps_word_t) wrapper,
|
||||
"getsize: non-data object.");
|
||||
return obj->data.numrefs;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
Now the useful things specially for checking the graph
|
||||
*/
|
||||
|
||||
/* recursively check the graph, starting at an object.
|
||||
We do the check twice, so as to restore the
|
||||
checkflags to zero.
|
||||
*/
|
||||
|
||||
static void checkloop(mycell *obj, int dir)
|
||||
{
|
||||
mycell *toj;
|
||||
int tid;
|
||||
int i;
|
||||
|
||||
asserts(obj->tag == MCdata + (mps_word_t) wrapper,
|
||||
"checkfrom: non data object in graph at %p.", obj);
|
||||
|
||||
if (obj->data.checkedflag != dir)
|
||||
{
|
||||
commentif(checkcomments, "checking %p = %li", obj, obj->data.id);
|
||||
|
||||
checkobjcount += 1;
|
||||
|
||||
obj->data.checkedflag = dir;
|
||||
|
||||
if (obj->data.assoc != NULL) {
|
||||
toj = obj->data.assoc;
|
||||
checkloop(toj, dir);
|
||||
}
|
||||
for (i=0; i<(obj->data.numrefs); i+=1)
|
||||
{
|
||||
if (obj->data.ref[i].addr != NULL)
|
||||
{
|
||||
toj = (obj->data.ref[i].addr);
|
||||
tid = (obj->data.ref[i].id);
|
||||
asserts(toj->data.id == tid,
|
||||
"checkfrom: corrupt graph at %p, %d.", obj, i);
|
||||
checkloop(toj, dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkfrom(mycell *obj)
|
||||
{
|
||||
int k;
|
||||
|
||||
freeze = 1; /* suspend counting while checking graph */
|
||||
checkobjcount = 0;
|
||||
checkloop(obj, 1);
|
||||
comment("checkfrom: %li live objects checked", checkobjcount);
|
||||
k = checkcomments;
|
||||
checkcomments = 0;
|
||||
checkloop(obj, 0);
|
||||
checkcomments = k;
|
||||
comment("checkfrom: graph ok from ID: %li.", obj->data.id);
|
||||
freeze = 0; /* resume counting */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------
|
||||
Now things to reset and display the counters
|
||||
*/
|
||||
|
||||
void resetcounters(void)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < PAD_COUNT+1; i++)
|
||||
{
|
||||
counters[i]=0;
|
||||
prevcounters[i]=0;
|
||||
maxcounters[i]=0;
|
||||
}
|
||||
maxcopy = 0;
|
||||
}
|
||||
|
||||
void updatecounters(void)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < PAD_COUNT+1; i++)
|
||||
{
|
||||
if (counters[i]-prevcounters[i] > maxcounters[i])
|
||||
{
|
||||
maxcounters[i]=counters[i]-prevcounters[i];
|
||||
}
|
||||
prevcounters[i]=counters[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void d_c(int i, char *name)
|
||||
{
|
||||
comment("%10d %s", counters[i], name);
|
||||
}
|
||||
|
||||
static void d_mc(int i, char *name)
|
||||
{
|
||||
comment("%10d %s", maxcounters[i], name);
|
||||
}
|
||||
|
||||
void displaycounters(void)
|
||||
{
|
||||
comment("--------");
|
||||
comment("Counters:");
|
||||
d_c(SCANCALL_COUNT, "scan calls");
|
||||
d_c(SCANOBJ_COUNT, "object scans");
|
||||
d_c(SCANHEART_COUNT, "heart scans");
|
||||
d_c(SCANPAD_COUNT, "pad scans");
|
||||
d_c(COPY_COUNT, "copys");
|
||||
d_c(SKIP_COUNT, "skips");
|
||||
d_c(FWD_COUNT, "fwds");
|
||||
d_c(ISFWD_COUNT, "isfwds");
|
||||
d_c(PAD_COUNT, "pads");
|
||||
d_c(RESERVE_COUNT, "reserve calls");
|
||||
d_c(ALLOC_COUNT, "allocations");
|
||||
d_c(DYING_REFERENCE_COUNT, "references fixed to NULL");
|
||||
comment("--------");
|
||||
}
|
||||
|
||||
void displaymaxcounters(void)
|
||||
{
|
||||
comment("--------");
|
||||
comment("Maximum counter values:");
|
||||
d_mc(SCANCALL_COUNT, "scan calls");
|
||||
d_mc(SCANOBJ_COUNT, "object scans");
|
||||
d_mc(SCANHEART_COUNT, "heart scans");
|
||||
d_mc(SCANPAD_COUNT, "pad scans");
|
||||
d_mc(COPY_COUNT, "copys");
|
||||
d_mc(SKIP_COUNT, "skips");
|
||||
d_mc(FWD_COUNT, "fwds");
|
||||
d_mc(ISFWD_COUNT, "isfwds");
|
||||
d_mc(RESERVE_COUNT, "reserve calls");
|
||||
d_mc(ALLOC_COUNT, "allocations");
|
||||
d_mc(DYING_REFERENCE_COUNT, "references fixed to NULL");
|
||||
d_mc(PAD_COUNT, "pads");
|
||||
comment("--------");
|
||||
comment("max copies of a single object: %li.", maxcopy);
|
||||
comment("--------");
|
||||
}
|
||||
|
||||
126
mps/qa/test/testlib/rankfmt.h
Normal file
126
mps/qa/test/testlib/rankfmt.h
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/* rankfmt.h
|
||||
Format like exfmt but with rank-checking built in.
|
||||
This format will work without register roots, but to use it,
|
||||
you must take precautions. You must register exfmt_root as
|
||||
a root, and unless you register the
|
||||
registers and stack, you must register it as ambiguous (or
|
||||
it might change before you can write the address of a newly
|
||||
allocated object into another root). When you call getref or
|
||||
setref, you must make sure that the objects concerned are
|
||||
referenced ambiguously somewhere (this guarantees that they
|
||||
won't move -- I asked richard and drj).
|
||||
|
||||
*/
|
||||
|
||||
#ifndef exfmt_h
|
||||
#define exfmt_h
|
||||
|
||||
#include "mps.h"
|
||||
|
||||
extern int formatcomments;
|
||||
extern int checkcomments;
|
||||
extern int countcomments;
|
||||
extern int alloccomments;
|
||||
extern int fixcomments;
|
||||
extern int deathcomments;
|
||||
extern int skipcomments;
|
||||
extern int splurgeassoc; /* write to associated objects (but don't change) */
|
||||
|
||||
extern mps_addr_t exfmt_root;
|
||||
|
||||
/* the counters are visible so that I can check whether things
|
||||
get moved etc
|
||||
*/
|
||||
|
||||
enum {
|
||||
SCANCALL_COUNT,
|
||||
SCANOBJ_COUNT, /* = read objects scanned */
|
||||
SCANPAD_COUNT, /* = pads scanned */
|
||||
SCANHEART_COUNT, /* = hearts scanned */
|
||||
COPY_COUNT,
|
||||
SKIP_COUNT,
|
||||
FWD_COUNT,
|
||||
ISFWD_COUNT,
|
||||
RESERVE_COUNT,
|
||||
ALLOC_COUNT,
|
||||
DYING_REFERENCE_COUNT,
|
||||
PAD_COUNT /* must come last or array sizes will be too small */
|
||||
};
|
||||
|
||||
extern int counters[PAD_COUNT+1];
|
||||
extern int prevcounters[PAD_COUNT+1];
|
||||
extern int maxcounters[PAD_COUNT+1];
|
||||
|
||||
long int maxcopy;
|
||||
int freeze;
|
||||
|
||||
/* the object format is visible so tests that want to
|
||||
can hack around with it
|
||||
*/
|
||||
|
||||
#define MAXSIZE 10000
|
||||
|
||||
enum {MCpad=(int) 0x1, MCheart=(int) 0x2, MCdata=(int) 0x0};
|
||||
|
||||
enum {MCerrorid=(int) 0xE6606};
|
||||
|
||||
/* n.b. MCerrorid < 0x1000000 so it won't clash with id of
|
||||
any ordinary object
|
||||
*/
|
||||
|
||||
typedef union mycell mycell;
|
||||
|
||||
typedef mps_word_t tag;
|
||||
|
||||
struct pad {tag tag;};
|
||||
|
||||
struct heart {tag tag; mps_addr_t obj; size_t size;};
|
||||
|
||||
struct data
|
||||
{
|
||||
tag tag;
|
||||
mycell *assoc;
|
||||
size_t size;
|
||||
long int id;
|
||||
long int copycount;
|
||||
long int numrefs;
|
||||
int checkedflag;
|
||||
mps_rank_t rank;
|
||||
struct refitem {mycell *addr; long int id;} ref[MAXSIZE];
|
||||
};
|
||||
|
||||
union mycell
|
||||
{
|
||||
tag tag;
|
||||
struct pad pad;
|
||||
struct heart heart;
|
||||
struct data data;
|
||||
};
|
||||
|
||||
extern struct mps_fmt_A_s fmtA;
|
||||
|
||||
mycell *allocone(mps_ap_t ap, int size, mps_rank_t rank);
|
||||
mycell *allocdumb(mps_ap_t ap, size_t bytes, mps_rank_t rank);
|
||||
|
||||
mps_addr_t getdata(mycell *obj);
|
||||
void setref(mycell *obj, int n, mycell *to);
|
||||
mycell *getref(mycell *obj, int n);
|
||||
|
||||
long int getid(mycell *obj);
|
||||
long int getcopycount(mycell *obj);
|
||||
long int getsize(mycell *obj);
|
||||
|
||||
void checkfrom(mycell *obj);
|
||||
|
||||
#define RC resetcounters()
|
||||
#define UC updatecounters()
|
||||
#define DC displaycounters()
|
||||
#define DMC displaymaxcounters()
|
||||
|
||||
void resetcounters(void);
|
||||
void updatecounters(void);
|
||||
void displaycounters(void);
|
||||
void displaymaxcounters(void);
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue