Plan 9 from Bell Labs’s /usr/web/sources/extra/i/gc.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include "i.h"

// Descriptors of all types that need to be garbage collected

typedef struct Descr Descr;

struct Descr {
	char* name;
	uchar size;		// in bytes; 0 means variable
	uchar align;
	uchar* members;
};

// keep this enum synchronized with descr table, below!
// start enum at 1 so 0 marks end of members array.
enum {
	DTchar = 1,	// 1 byte
	DTshort,		// 2 bytes
	DTlong,		// 4 bytes
	DTstring,		// ptr to null terminated char array
	DTString,		// ptr to null terminated Rune array
	DTptr,		// followed by code for pointed-to object
	DTptrnogc,	// pointer to stuff from usual malloc regime (just copy)
	DTptrnogcnil,	// pointer that should be nil at gc time
	DTarray,		// next two bytes are length, high order first
				// ((255,x) means use x as signed char byte offset
				//  from array start  to long elem count)),
				// then code for element type
	DTptrarray,	// pointer to array
				// next two bytes are length (as in DTarray), with
				// count offset relative to this ptr in current struct
	DTptrarray2d,	// pointer to array of arrays, both counts in this struct
				// first comes count for rows
				// then count for cols, then elem type
	DTunion,		// union assumed to start with a long tag.
				// following byte is DT code for type (of data following tag)
				// correponding to tag==0, and rest of variants are
				// assumed sequential after that,
				// up until (and including) code of next byte
	DTvunion,	// "variable union": i.e., different variants are allocated
				// at different lengths.
				// following byte is offset to long tag.
				// then comes DT code for type (of all data in the vunion)
				// correponding to tag==0, and rest of variants are
				// assumed sequential after that
				// up until (and including) code of next byte

	NUMBUILTINDTS,

	// from draw.h
	DTPoint = NUMBUILTINDTS,
	DTRectangle,

	// from i.h
	DTList,
	DTStrlist,
	DTParsedUrl,
	DTStringInt,
	DTConfig,
	DTReqInfo,
	DTMaskedImage,
	DTCImage,
	DTHeader,
	DTResourceState,
	DTToken,
	DTAttr,
	DTAlign,
	DTDimen,
	DTBackground,
	DTItem,
	DTItext,
	DTIrule,
	DTIimage,
	DTIformfield,
	DTItable,
	DTIfloat,
	DTIspacer,
	DTItemlist,
	DTGenattr,
	DTFormfield,
	DTOption,
	DTForm,
	DTTable,
	DTTablecol,
	DTTablerow,
	DTTablecell,
	DTAnchor,
	DTDestAnchor,
	DTMap,
	DTArea,
	DTKidinfo,
	DTDocinfo,
	DTFrame,
	DTFramelist,
	DTLine,
	DTLoc,
	DTLocelem,
	DTControl,
	DTCbutton,
	DTCentry,
	DTCcheckbox,
	DTCselect,
	DTCscrollbar,
	DTCanimimage,
	DTCprogbox,
	DTClabel,
	DTLay,
	DTEV,
	DTEVkey,
	DTEVmouse,
	DTEVmove,
	DTEVresize,
	DTEVexpose,
	DTEVhide,
	DTEVquit,
	DTEVstop,
	DTEValert,
	DTEVform,
	DTEVgo,
	DTEVanim,
	DTEVprogress,
	DTEVdelay,
	DTScriptEvent,
	DTGoSpec,
	DTDocConfig,
	DTHistNode,
	DTHistNode_list,
	DTHistory,
	DTAuthInfo,
	DTCtlLayout,
	DTProgLayout,
	DTPopupLayout,
	DTPopupAns,

	NUMDTS
};

// (acid used to derive the descriptor tables)
static uchar d_point[] = { DTlong, DTlong, 0 };
static uchar d_rectangle[] = { DTPoint, DTPoint, 0 };
static uchar d_list[] = { DTptr, DTList, DTlong, 0 };
static uchar d_strlist[]= { DTptr, DTStrlist, DTString, 0 };
static uchar d_parsedurl[] = { DTarray, 0, 18, DTlong,
		DTarray, 255, (uchar)((signed char)-4), DTshort, 0 };
static uchar d_stringint[] = { DTString, DTlong, 0 };
static uchar d_config[] = {
	DTString,				// userdir
	DTptr, DTParsedUrl,		// starturl
	DTptr, DTParsedUrl,		// homeurl
	DTptr, DTParsedUrl,		// httpproxy
	DTlong,				// defaultwidth
	DTlong,				// defaultheight
	DTlong,				// x
	DTlong,				// y
	DTlong,				// nocache
	DTlong,				// maxstale
	DTlong,				// imagelvl
	DTlong,				// imagecachenum
	DTlong,				// imagecachemem
	DTlong,				// docookies
	DTlong,				// doscripts
	DTlong,				// saveauthinfo
	DTlong,				// showprogress
	DTlong,				// usecci
	DTlong,				// httpminor
	DTString,				// agentname
	DTlong,				// nthreads
	DTString,				// dbgfile
	DTarray, 0, 128, DTchar,	// dbg
	0 };
static uchar d_reqinfo[] = { DTptr, DTParsedUrl, DTlong,
	DTstring, DTlong, DTString, DTlong, 0 };
static uchar d_maskedimage[] = { DTptrnogc, DTptrnogc,
	DTlong, DTlong, DTlong, DTPoint, 0 };
static uchar d_cimage[] = { DTptr, DTCImage,
	DTptr, DTParsedUrl,
	DTptr, DTParsedUrl,
	DTlong, DTlong, DTlong, DTlong,
	DTptrarray, 255, 4, DTptr, DTMaskedImage,
	DTlong, 0 };
static uchar d_header[] = { DTlong,
	DTptr, DTParsedUrl, DTptr, DTParsedUrl, DTptr, DTParsedUrl,
	DTlong, DTlong, DTlong,
	DTString, DTString, DTString, DTString, 0 };
static uchar d_resourcestate[] = { DTlong, DTlong, DTlong, 0 };
static uchar d_token[] = { DTlong, DTString, DTptr, DTAttr, DTlong, 0 };
static uchar d_attr[] = { DTptr, DTAttr, DTlong, DTString, 0 };
static uchar d_align[] = { DTchar, DTchar, 0 };
static uchar d_dimen[] = { DTlong, 0 };
static uchar d_background[] = { DTptr, DTCImage, DTlong, 0 };
static uchar d_item[] = { DTvunion, 28, DTItext,  DTIspacer, 0 };
static uchar d_itext[] = { DTptr, DTItem,
	DTlong, DTlong, DTlong, DTlong, DTlong, DTptr, DTGenattr, DTlong,
	DTString, DTlong,DTlong, DTchar, DTchar, 0 };
static uchar d_irule[] = { DTptr, DTItem,
	DTlong, DTlong, DTlong, DTlong, DTlong, DTptr, DTGenattr, DTlong,
	DTchar, DTchar, DTlong, DTDimen, 0 };
static uchar d_iimage[] = { DTptr, DTItem,
	DTlong, DTlong, DTlong, DTlong, DTlong, DTptr, DTGenattr, DTlong,
	DTptr, DTCImage, DTlong, DTlong,	// ci, imwidth, imheight
	DTString, DTptr, DTMap, DTlong,	// altrep, map, ctlid
	DTchar, DTchar, DTchar, DTchar,	// align, hspace, vspace, border
	DTptr, DTIimage,				// nextimage
	0 };
static uchar d_iformfield[] = { DTptr, DTItem,
	DTlong, DTlong, DTlong, DTlong, DTlong, DTptr, DTGenattr, DTlong,
	DTptr, DTFormfield, 0 };
static uchar d_itable[] = { DTptr, DTItem,
	DTlong, DTlong, DTlong, DTlong, DTlong, DTptr, DTGenattr, DTlong,
	DTptr, DTTable, 0 };
static uchar d_ifloat[] = { DTptr, DTItem,
	DTlong, DTlong, DTlong, DTlong, DTlong, DTptr, DTGenattr, DTlong,
	DTptr, DTItem, DTlong, DTlong, DTchar, DTchar, DTptr, DTIfloat, 0 };
static uchar d_ispacer[] = { DTptr, DTItem,
	DTlong, DTlong, DTlong, DTlong, DTlong, DTptr, DTGenattr, DTlong,
	DTlong, 0 };
static uchar d_iitemlist[] = { DTptr, DTItemlist, DTptr, DTItem, 0 };
static uchar d_genattr[] = { DTString, DTString, DTString, DTString,
	DTptr, DTAttr, 0 };
static uchar d_formfield[] = { DTptr, DTFormfield,
	DTlong, DTlong, DTptr, DTForm, DTString, DTString,
	DTlong, DTlong, DTlong, DTlong,
	DTchar, DTptr, DTOption, DTptr, DTItem,
	DTlong, DTptr, DTAttr, 0 };
static uchar d_option[] = { DTptr, DTOption, DTlong, DTString, DTString, 0 };
static uchar d_form[] = { DTptr, DTForm,
	DTlong, DTString, DTptr, DTParsedUrl,
	DTlong, DTlong, DTlong, DTptr, DTFormfield, 0 };
static uchar d_table[] = { DTptr, DTTable, DTlong,
	DTlong, DTptrarray, 255, 4, DTTablerow,	// NOTE: don't gc during parsing!
	DTlong, DTptrarray, 255, 4, DTTablecol,
	DTptr, DTTablecell, DTlong,
	DTptrarray2d, 255, (uchar)-20, 255, (uchar)-12, DTptr, DTTablecell,
	DTAlign, DTDimen,
	DTlong, DTlong, DTlong,
	DTBackground,
	DTptr, DTItem, DTchar, DTptr, DTLay,
	DTlong, DTlong, DTlong, DTlong,
	DTptr, DTToken, DTchar,
	0 };
static uchar d_tablecol[] = { DTlong, DTAlign, DTPoint, 0 };
static uchar d_tablerow[] = { DTptr, DTTablerow, DTptr, DTTablecell,
	DTlong, DTlong, DTAlign, DTBackground, DTPoint, DTchar, 0 };
static uchar d_tablecell[] = { DTptr, DTTablecell, DTptr, DTTablecell,
	DTlong, DTptr, DTItem, DTptr, DTLay,
	DTlong, DTlong,
	DTAlign, DTchar, DTDimen,
	DTlong, DTBackground,
	DTlong, DTlong, DTlong, DTlong, DTlong, DTPoint, 0 };
static uchar d_anchor[] = { DTptr, DTAnchor,
	DTlong, DTString, DTptr, DTParsedUrl, DTlong, 0 };
static uchar d_destanchor[] = { DTptr, DTDestAnchor,
	DTlong, DTString, DTptr, DTItem, 0 };
static uchar d_map[] = { DTptr, DTMap, DTString, DTptr, DTArea, 0};
static uchar d_area[] = { DTptr, DTArea, DTlong,
	DTptr, DTParsedUrl, DTlong, DTptrarray, 255, 4, DTDimen, DTlong, 0 };
static uchar d_kidinfo[] = { DTptr, DTKidinfo, DTlong,
	DTptr, DTParsedUrl, DTString, DTlong, DTlong, DTlong, DTlong,
	DTptrarray, 255, 4, DTDimen, DTlong,
	DTptrarray, 255, 4, DTDimen, DTlong,
	DTptr, DTKidinfo, DTptr, DTKidinfo, 0 };
static uchar d_docinfo[] = { 
	DTptr, DTParsedUrl, DTptr, DTParsedUrl,	// src, base
	DTString, DTBackground,				// doctitle, background
	DTptr, DTIimage,					// backgrounditem
	DTlong, DTlong, DTlong, DTlong,		// text, link, vlink, alink
	DTlong, DTlong, DTlong, DTlong,		// target, chset, scripttype, hasscripts
	DTString, DTptr, DTKidinfo, DTlong,		// refresh, kidinfo, frameid
	DTptr, DTAnchor, DTptr, DTDestAnchor,	// anchors, dests
	DTptr, DTForm, DTptr, DTTable,		// forms, tables
	DTptr, DTMap, DTptr, DTIimage,		// maps, images
	0 };
static uchar d_frame[] = {
	DTlong, DTptr, DTDocinfo,			// id, doc
	DTptr, DTParsedUrl, DTString,			// src, name
	DTlong, DTlong, DTlong, DTlong,		// marginw, marginh, framebd, flags
	DTptr, DTLay,						// layout
	DTptrarray, 255, 4, DTptr, DTControl,	// controls
	DTlong, DTlong,					// controlslen, controlid
	DTptrnogc,						// cim
	DTRectangle, DTRectangle,			// r, cr
	DTRectangle, DTRectangle,			// totalr, viewr
	DTptr, DTControl, DTptr, DTControl,	// vscr, hscr
	DTptr, DTFrame, DTptr, DTFramelist,	// parent, kids
	0 };
static uchar d_framelist[] = {
	DTptr, DTFramelist, DTptr, DTFrame, 0 };
static uchar d_line[] = { DTptr, DTLine, DTptr, DTLine,
	DTptr, DTItem, DTPoint, DTlong, DTlong, DTlong, DTchar, 0 };
static uchar d_loc[] = { DTptrarray, 255, 4, DTLocelem,
	DTlong, DTlong, DTPoint, 0 };
static uchar d_locelem[] = { DTlong, DTPoint,
	DTptr, DTFrame, DTptr, DTLine, DTptr, DTItem,
	DTptr, DTTablecell, DTptr, DTControl, 0 };
static uchar d_control[] = { DTvunion, 16, DTCbutton, DTClabel, 0 };
static uchar d_cbutton[] = { DTptr, DTFrame, DTptr, DTFormfield,
	DTRectangle, DTlong, DTlong,
	DTptrnogc, DTptrnogc, DTptrnogc, DTptrnogc, DTString, DTlong,
	0 };
static uchar d_centry[] = { DTptr, DTFrame, DTptr, DTFormfield,
	DTRectangle, DTlong, DTlong,
	DTString, DTlong, DTlong, DTlong,
	0 };
static uchar d_ccheckbox[] = { DTptr, DTFrame, DTptr, DTFormfield,
	DTRectangle, DTlong, DTlong,
	DTlong, 0 };
static uchar d_cselect[] = { DTptr, DTFrame, DTptr, DTFormfield,
	DTRectangle, DTlong, DTlong,
	DTptr, DTCscrollbar, DTlong, DTlong, DTptr, DTOption, DTlong,
	0 };
static uchar d_cscrollbar[] = { DTptr, DTFrame, DTptr, DTFormfield,
	DTRectangle, DTlong, DTlong,
	DTlong, DTlong, DTlong, DTlong, DTptr, DTControl,
	0 };
static uchar d_canimimage[] = { DTptr, DTFrame, DTptr, DTFormfield,
	DTRectangle, DTlong, DTlong,
	DTptr, DTCImage, DTlong, DTlong, DTBackground,
	0 };
static uchar d_cprogbox[] = { DTptr, DTFrame, DTptr, DTFormfield,
	DTRectangle, DTlong, DTlong,
	DTlong, DTlong, DTlong, DTString, DTString,
	0 };
static uchar d_clabel[] = { DTptr, DTFrame, DTptr, DTFormfield,
	DTRectangle, DTlong, DTlong,
	DTString,
	0 };
static uchar d_lay[] = { DTptr, DTLine, DTptr, DTLine,
	DTlong, DTlong, DTlong, DTlong,
	DTptr, DTIfloat, DTBackground, DTchar, DTchar, 0 };
static uchar d_ev[] = { DTunion, DTEVkey, DTEVdelay, 0 };
static uchar d_evkey[] = { DTlong, DTlong, 0 };
static uchar d_evmouse[] = { DTlong, DTPoint, DTlong, 0 };
static uchar d_evmove[] = { DTlong, DTPoint, 0 };
static uchar d_evresize[] = { DTlong, DTRectangle, 0 };
static uchar d_evexpose[] = { DTlong, 0 };
static uchar d_evhide[] = { DTlong, 0 };
static uchar d_evquit[] = { DTlong, 0 };
static uchar d_evstop[] = { DTlong, 0 };
static uchar d_evalert[] = { DTlong, DTString, DTptrnogc, 0 };
static uchar d_evform[] = { DTlong, DTlong, DTlong, DTlong, 0 };
static uchar d_evgo[] = { DTlong, DTptr, DTParsedUrl, DTlong, DTlong, 0 };
static uchar d_evanim[] = { DTlong, DTlong, DTptr, DTCanimimage, 0 };
static uchar d_evprogress[] = { DTlong, DTlong, DTlong, DTlong, DTString, 0 };
static uchar d_evdelay[] = { DTlong, DTlong, DTptr, DTEV, 0 };
static uchar d_scriptevent[] = { DTarray, 0, 8, DTlong, 0 };
static uchar d_gospec[] = { DTlong, DTptr, DTParsedUrl,
	DTlong, DTString, DTlong, DTString, DTptr, DTHistNode, 0 };
static uchar d_docconfig[] = { DTString, DTString, DTlong, DTptr, DTGoSpec, 0 };
static uchar d_histnode[] = { DTptr, DTDocConfig,
	DTptrarray, 255, 4, DTptr, DTDocConfig, DTlong,
	DTptr, DTHistNode_list, DTptr, DTHistNode_list, 0 };
static uchar d_histnode_list[] = { DTptr, DTHistNode_list, DTptr, DTHistNode, 0 };
static uchar d_history[] = { DTptrarray, 255, 4, DTlong, DTlong, DTlong, 0 };
static uchar d_authinfo[] = { DTptr, DTAuthInfo, DTString, DTString, 0 };
static uchar d_ctllayout[] = { DTptrnogc,
	DTPoint, DTPoint, DTPoint, DTPoint,
	DTarray, 0, NUMCLCS, DTptr, DTControl, DTString, 0 };
static uchar d_proglayout[] = { DTptrarray, 255, 4, DTptr, DTControl,
	DTlong, DTlong, DTPoint, DTlong, 0 };
static uchar d_popuplayout[] = { DTlong,
	DTptrarray, 255, 4, DTptr, DTControl, DTlong,
	DTptr, DTControl, DTptr, DTControl, 0 };
static uchar d_popupans[] = { DTlong, DTString, 0 };

// keep this table synchronized with DT enum!
Descr descr[] = {
	{ "dummy", 0, 0, nil },
	{ "char", sizeof(char), sizeof(char), nil },
	{ "short", sizeof(short), sizeof(short), nil },
	{ "long", sizeof(long), sizeof(long), nil },
	{ "string", sizeof(void*), sizeof(void*), nil },
	{ "String", sizeof(void*), sizeof(void*), nil },
	{ "ptr", sizeof(void*), sizeof(void*), nil },
	{ "ptrnogc", sizeof(void*), sizeof(void*), nil },
	{ "ptrnogcnil", sizeof(void*), sizeof(void*), nil },
	{ "array", 0, 4, nil },
	{ "ptrarray", sizeof(void*), sizeof(void*), nil },
	{ "ptrarray2d", sizeof(void*), sizeof(void*), nil },
	{ "union", 0, 4, nil },
	{ "vunion", 0, 4, nil },
	{ "Point", sizeof(Point), 4, d_point },
	{ "Rectangle", sizeof(Rectangle), 4, d_rectangle },
	{ "List", sizeof(List), 4, d_list },
	{ "Strlist", sizeof(Strlist), 4, d_strlist },
	{ "ParsedUrl", 0, 4, d_parsedurl },
	{ "StringInt", sizeof(StringInt), 4, d_stringint },
	{ "Config", sizeof(Config), 4, d_config },
	{ "ReqInfo", sizeof(ReqInfo), 4, d_reqinfo },
	{ "MaskedImage", sizeof(MaskedImage), 4, d_maskedimage },
	{ "CImage", sizeof(CImage), 4, d_cimage },
	{ "Header", sizeof(Header), 4, d_header },
	{ "ResourceState", sizeof(ResourceState), 4, d_resourcestate },
	{ "Token", sizeof(Token), 4, d_token },
	{ "Attr", sizeof(Attr), 4, d_attr },
	{ "Align", sizeof(Align), 4, d_align },
	{ "Dimen", sizeof(Dimen), 4, d_dimen },
	{ "Background", sizeof(Background), 4, d_background },
	{ "Item", 0, 4, d_item },
	{ "Itext", sizeof(Itext), 4, d_itext },
	{ "Irule", sizeof(Irule), 4, d_irule },
	{ "Iimage", sizeof(Iimage), 4, d_iimage },
	{ "Iformfield", sizeof(Iformfield), 4, d_iformfield },
	{ "Itable", sizeof(Itable), 4, d_itable },
	{ "Ifloat", sizeof(Ifloat), 4, d_ifloat },
	{ "Ispacer", sizeof(Ispacer), 4, d_ispacer },
	{ "Itemlist", sizeof(Itemlist), 4, d_iitemlist },
	{ "Genattr", sizeof(Genattr), 4, d_genattr },
	{ "Formfield", sizeof(Formfield), 4, d_formfield },
	{ "Option", sizeof(Option), 4, d_option },
	{ "Form", sizeof(Form), 4, d_form },
	{ "Table", sizeof(Table), 4, d_table },
	{ "Tablecol", sizeof(Tablecol), 4, d_tablecol },
	{ "Tablerow", sizeof(Tablerow), 4, d_tablerow },
	{ "Tablecell", sizeof(Tablecell), 4, d_tablecell },
	{ "Anchor", sizeof(Anchor), 4, d_anchor },
	{ "DestAnchor", sizeof(DestAnchor), 4, d_destanchor },
	{ "Map", sizeof(Map), 4, d_map },
	{ "Area", sizeof(Area), 4, d_area },
	{ "Kidinfo", sizeof(Kidinfo), 4, d_kidinfo },
	{ "Docinfo", sizeof(Docinfo), 4, d_docinfo },
	{ "Frame", sizeof(Frame), 4, d_frame },
	{ "Framelist", sizeof(Framelist), 4, d_framelist },
	{ "Line", sizeof(Line), 4, d_line },
	{ "Loc", sizeof(Loc), 4, d_loc },
	{ "Locelem", sizeof(Locelem), 4, d_locelem },
	{ "Control", 0, 4, d_control },
	{ "Cbutton", sizeof(Cbutton), 4, d_cbutton },
	{ "Centry", sizeof(Centry), 4, d_centry },
	{ "Ccheckbox", sizeof(Ccheckbox), 4, d_ccheckbox },
	{ "Cselect", sizeof(Cselect), 4, d_cselect },
	{ "Cscrollbar", sizeof(Cscrollbar), 4, d_cscrollbar },
	{ "Canimimage", sizeof(Canimimage), 4, d_canimimage },
	{ "Cprogbox", sizeof(Cprogbox), 4, d_cprogbox },
	{ "Clabel", sizeof(Clabel), 4, d_clabel },
	{ "Lay", sizeof(Lay), 4, d_lay },
	{ "EV", sizeof(EV), 4, d_ev },
	{ "EVkey", 8, 4, d_evkey },
	{ "EVmouse", 16, 4, d_evmouse },
	{ "EVmove", 12, 4, d_evmove },
	{ "EVresize", 20, 4, d_evresize },
	{ "EVexpose", 4, 4, d_evexpose },
	{ "EVhide", 4, 4, d_evhide },
	{ "EVquit", 4, 4, d_evquit },
	{ "EVstop", 4, 4, d_evstop },
	{ "EValert", 12, 4, d_evalert },
	{ "EVform", 16, 4, d_evform },
	{ "EVgo", 16, 4, d_evgo },
	{ "EVanim", 12, 4, d_evanim },
	{ "EVprogress", 20, 4, d_evprogress },
	{ "EVdelay", 12, 4, d_evdelay },
	{ "ScriptEvent", sizeof(ScriptEvent), 4, d_scriptevent },
	{ "GoSpec", sizeof(GoSpec), 4, d_gospec },
	{ "DocConfig", sizeof(DocConfig), 4, d_docconfig },
	{ "HistNode", sizeof(HistNode), 4, d_histnode },
	{ "HistNode_list", sizeof(HistNode_list), 4, d_histnode_list },
	{ "History", sizeof(History), 4, d_history },
	{ "AuthInfo", sizeof(AuthInfo), 4, d_authinfo },
	{ "CtlLayout", sizeof(CtlLayout), 4, d_ctllayout },
	{ "ProgLayout", sizeof(ProgLayout), 4, d_proglayout },
	{ "PopupLayout", sizeof(PopupLayout), 4, d_popuplayout },
	{ "PopupAns", sizeof(PopupAns), 4, d_popupans },
};

static int calcsizeof(int ty);
static void checkgctables(void);

// al is power of two.
// round n up to nearest multiple of al, if not already one.
// assume n >= 0.
static int
alignto(int n, int al)
{
	ulong m;

	m = al-1;
	if((n&m) != 0)
		n = (n+al)&(~m);
	return n;
}

// v should point at a 2-byte count (possibly
// a "variable" count, with 255 in first byte).
// skip over it, and put pointer to count in *pcnt,
// using -1 if variable and putting offset into *poff.
// return pointer to just after the type.
static uchar*
skipcount(uchar* v, int* pcnt, int *poff)
{
	int a, c, o;

	a = *v++;
	if(a == 255) {
		c = -1;
		o = (signed char)(*v++);
		assert((o&3)==0);
	}
	else {
		c = (a<<8) | *v++;
		o = 0;
		assert(c < 1000);	// currently bigger than any static array
	}
	*pcnt = c;
	*poff = o;
	return v;
}

// v should point at type (may be variable length).
// skip over the type, doing sanity checks,
// and return pointer to just after the type.
static uchar*
skiptype(uchar* v)
{
	int t, t2, c, o;

	t = *v++;
	assert(t >= 1 && t < NUMDTS);
	switch(t) {
	case DTptr:
		v = skiptype(v);
		break;
	case DTptrnogc:
	case DTptrnogcnil:
		break;
	case DTarray:
	case DTptrarray:
		v = skipcount(v, &c, &o);
		v = skiptype(v);
	case DTptrarray2d:
		v = skipcount(v, &c, &o);
		v = skipcount(v, &c, &o);
		v = skiptype(v);
		break;
	case DTunion:
		t = *v++;
		assert(t >= NUMBUILTINDTS && t < NUMDTS);
		t2 = *v++;
		assert(t2 > t && t2 < NUMDTS);
		break;
	case DTvunion:
		o = (signed char)(*v++);
		assert((o&3) == 0);
		t = *v++;
		assert(t >= NUMBUILTINDTS && t < NUMDTS);
		t2 = *v++;
		assert(t2 > t && t2 < NUMDTS);
		break;
	}
	return v;
}

// Calculate sizeof one member, whose description
// starts at *v.
// Put size in *psz (-1 if variable size), and return updated v.
static uchar*
calcsizeof1(uchar* v, int* psz)
{
	int t, t2, n, c, o;
	Descr* d;

	t = *v++;
	assert(t >= 1 && t < NUMDTS);
	d = &descr[t];
	n = 0;
	switch(t) {
	case DTptr:
		n = d->size;
		v = skiptype(v);
		break;
	case DTptrnogc:
	case DTptrnogcnil:
		n = d->size;
		break;
	case DTarray:
		v = skipcount(v, &n, &o);
		if(n != -1) {
			v = calcsizeof1(v, &c);
			if(c == -1)
				n = -1;
			else
				n *= c; 
		}
		break;
	case DTptrarray:
		n = d->size;
		v = skipcount(v, &c, &o);
		v = skiptype(v);
		break;
	case DTptrarray2d:
		n = d->size;
		v = skipcount(v, &c, &o);
		v = skipcount(v, &c, &o);
		v = skiptype(v);
		break;
	case DTunion:
		t = *v++;
		assert(t >= NUMBUILTINDTS && t < NUMDTS);
		t2 = *v++;
		assert(t2 > t && t2 < NUMDTS);
		for( ; t <= t2; t++) {
			c = calcsizeof(t);
			assert(c != -1);
			if(c > n)
				n = c;
		}
		n += sizeof(long);	// for tag
		break;
	case DTvunion:
		o = (signed char)(*v++);
		assert((o&3) == 0);
		t = *v++;
		assert(t >= NUMBUILTINDTS && t < NUMDTS);
		t2 = *v++;
		assert(t2 > t && t2 < NUMDTS);
		n = -1;
		break;
	default:
		n = d->size;
	}
	*psz = n;
	return v;
}

// Calculate sizeof type ty using the information
// in the tables.  Return -1 if size is variable.
// The answer should match the size member of descr.
// Also, make various sanity checks.
static int
calcsizeof(int ty)
{
	int n, k, t;
	uchar* v;

	v = descr[ty].members;
	if(v == nil)
		return descr[ty].size;
	n = 0;
	while(*v != 0) {
		t = *v;
		assert(t >= 1 && t < NUMDTS);
		n = alignto(n, descr[t].align);
		v = calcsizeof1(v, &k);
		if(k == -1)
			return -1;
		n += k;
	}
	return alignto(n, descr[ty].align);
}

// Do sanity checks on the tables
static void
checkgctables()
{
	int t, n, numerrs;

	assert(sizeof(descr)/sizeof(descr[0]) == NUMDTS);
	numerrs = 0;
	for(t = NUMBUILTINDTS; t < NUMDTS; t++) {
		assert(descr[t].align == 4);	// no doubles in our structures, for now
		n = calcsizeof(t);
		if(!(n == -1 || n == descr[t].size)) {
			trace("problem with gctable for %s:\n", descr[t].name);
			trace("calculated size=%d, sizeof=%d\n", n, descr[t].size);
			numerrs++;
		}
	}
	assert(numerrs == 0);
}

void
gcinit()
{
	if(dbg)
		checkgctables();
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.