codgen(Node *n, Node *nn)
{
Prog *sp;
- Node *n1, nod, nod1;
- Sym *gcsym;
- static int ngcsym;
+ Node *n1, nod, nod1, nod2;
+ Sym *gcsym, *gclocalssym;
+ static int ngcsym, ngclocalssym;
static char namebuf[40];
int32 off;
nod.op = ONAME;
nod.sym = gcsym;
nod.class = CSTATIC;
- gins(AFUNCDATA, nodconst(FUNCDATA_GC), &nod);
+ gins(AFUNCDATA, nodconst(FUNCDATA_GCArgs), &nod);
+
+ snprint(namebuf, sizeof(namebuf), "gclocalssym·%d", ngclocalssym++);
+ gclocalssym = slookup(namebuf);
+ gclocalssym->class = CSTATIC;
+
+ memset(&nod2, 0, sizeof(nod2));
+ nod2.op = ONAME;
+ nod2.sym = gclocalssym;
+ nod2.class = CSTATIC;
+ gins(AFUNCDATA, nodconst(FUNCDATA_GCLocals), &nod2);
/*
* isolate first argument
// That said, we've been using stkoff for months
// and nothing too terrible has happened.
off = 0;
- gextern(gcsym, nodconst(stkoff), off, 4); // locals
- off += 4;
off = pointermap(gcsym, off); // nptrs and ptrs[...]
gcsym->type = typ(0, T);
gcsym->type->width = off;
+
+ off = 0;
+ gextern(gclocalssym, nodconst(-stkoff), off, 4); // locals
+ off += 4;
+ gclocalssym->type = typ(0, T);
+ gclocalssym->type->width = off;
}
void
#include "../../pkg/runtime/funcdata.h"
static void allocauto(Prog* p);
-static int pointermap(Sym*, int, Node*);
-static void gcsymbol(Sym*, Node*);
+static void dumpgcargs(Node*, Sym*);
+static void dumpgclocals(Node*, Sym*);
void
compile(Node *fn)
{
Plist *pl;
- Node nod1, *n, *gcnod;
+ Node nod1, *n, *gcargsnod, *gclocalsnod;
Prog *ptxt, *p, *p1;
int32 lno;
Type *t;
Iter save;
vlong oldstksize;
NodeList *l;
- Sym *gcsym;
- static int ngcsym;
+ Sym *gcargssym, *gclocalssym;
+ static int ngcargs, ngclocals;
if(newproc == N) {
newproc = sysfunc("newproc");
ginit();
- snprint(namebuf, sizeof namebuf, "gc·%d", ngcsym++);
- gcsym = lookup(namebuf);
- gcnod = newname(gcsym);
- gcnod->class = PEXTERN;
+ snprint(namebuf, sizeof namebuf, "gcargs·%d", ngcargs++);
+ gcargssym = lookup(namebuf);
+ gcargsnod = newname(gcargssym);
+ gcargsnod->class = PEXTERN;
- nodconst(&nod1, types[TINT32], FUNCDATA_GC);
- gins(AFUNCDATA, &nod1, gcnod);
+ nodconst(&nod1, types[TINT32], FUNCDATA_GCArgs);
+ gins(AFUNCDATA, &nod1, gcargsnod);
+
+ snprint(namebuf, sizeof(namebuf), "gclocals·%d", ngclocals++);
+ gclocalssym = lookup(namebuf);
+ gclocalsnod = newname(gclocalssym);
+ gclocalsnod->class = PEXTERN;
+
+ nodconst(&nod1, types[TINT32], FUNCDATA_GCLocals);
+ gins(AFUNCDATA, &nod1, gclocalsnod);
for(t=curfn->paramfld; t; t=t->down)
gtrack(tracksym(t->type));
oldstksize = stksize;
allocauto(ptxt);
-
- // Emit garbage collection symbol.
- gcsymbol(gcsym, fn);
if(0)
print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
setlineno(curfn);
- if((int64)stksize+maxarg > (1ULL<<31))
+ if((int64)stksize+maxarg > (1ULL<<31)) {
yyerror("stack frame too large (>2GB)");
+ goto ret;
+ }
defframe(ptxt);
if(0)
frame(0);
+ // Emit garbage collection symbols.
+ dumpgcargs(fn, gcargssym);
+ dumpgclocals(curfn, gclocalssym);
+
ret:
lineno = lno;
}
-static void
-gcsymbol(Sym *gcsym, Node *fn)
-{
- int off;
-
- off = 0;
- off = duint32(gcsym, off, stksize); // size of local block
- off = pointermap(gcsym, off, fn); // pointer bitmap for args (must be last)
- ggloblsym(gcsym, off, 0, 1);
-}
-
static void
walktype1(Type *t, vlong *xoffset, Bvec *bv)
{
}
// Compute a bit vector to describes the pointer containing locations
-// in the argument list.
-static int
-pointermap(Sym *gcsym, int off, Node *fn)
+// in the in and out argument list and dump the bitvector length and
+// data to the provided symbol.
+static void
+dumpgcargs(Node *fn, Sym *sym)
{
Type *thistype, *inargtype, *outargtype;
Bvec *bv;
int32 i;
+ int off;
thistype = getthisx(fn->type);
inargtype = getinargx(fn->type);
walktype(inargtype, bv);
if(outargtype != nil)
walktype(outargtype, bv);
- off = duint32(gcsym, off, bv->n);
+ off = duint32(sym, 0, bv->n);
for(i = 0; i < bv->n; i += 32)
- off = duint32(gcsym, off, bv->b[i/32]);
+ off = duint32(sym, off, bv->b[i/32]);
+ free(bv);
+ ggloblsym(sym, off, 0, 1);
+}
+
+// Compute a bit vector to describes the pointer containing locations
+// in local variables and dumps the bitvector length and data out to
+// the provided symbol.
+static void
+dumpgclocals(Node* fn, Sym *sym)
+{
+ Bvec *bv;
+ NodeList *ll;
+ Node *node;
+ vlong xoffset;
+ int32 i;
+ int off;
+
+ bv = bvalloc(rnd(stksize, widthptr) / widthptr);
+ for(ll = fn->dcl; ll != nil; ll = ll->next) {
+ node = ll->n;
+ if(node->class == PAUTO && node->op == ONAME) {
+ if(haspointers(node->type)) {
+ xoffset = node->xoffset + rnd(stksize,widthptr);
+ walktype1(node->type, &xoffset, bv);
+ }
+ }
+ }
+ off = duint32(sym, 0, bv->n);
+ for(i = 0; i < bv->n; i += 32) {
+ off = duint32(sym, off, bv->b[i/32]);
+ }
free(bv);
- return off;
+ ggloblsym(sym, off, 0, 1);
}
// Sort the list of stack variables. autos after anything else,
extern byte pclntab[]; // base for f->ptrsoff
-typedef struct GCFunc GCFunc;
-struct GCFunc
+typedef struct BitVector BitVector;
+struct BitVector
{
- uint32 locals; // size of local variables in bytes
- uint32 nptrs; // number of words that follow
- uint32 ptrs[1]; // bitmap of pointers in arguments
+ int32 n;
+ uint32 data[];
};
+// Starting from scanp, scans words corresponding to set bits.
+static void
+scanbitvector(byte *scanp, BitVector *bv)
+{
+ uint32 *wp;
+ uint32 w;
+ int32 i, remptrs;
+
+ wp = bv->data;
+ for(remptrs = bv->n; remptrs > 0; remptrs -= 32) {
+ w = *wp++;
+ if(remptrs < 32)
+ i = remptrs;
+ else
+ i = 32;
+ for(; i > 0; i--) {
+ if(w & 1)
+ addroot((Obj){scanp, PtrSize, 0});
+ w >>= 1;
+ scanp += PtrSize;
+ }
+ }
+}
+
// Scan a stack frame: local variables and function arguments/results.
static void
addframeroots(Stkframe *frame, void*)
{
Func *f;
- byte *ap;
- int32 i, j, nuintptr;
- uint32 w, b;
- GCFunc *gcf;
+ BitVector *args, *locals;
+ uintptr size;
f = frame->fn;
- gcf = runtime·funcdata(f, FUNCDATA_GC);
-
+
// Scan local variables if stack frame has been allocated.
- i = frame->varp - (byte*)frame->sp;
- if(i > 0) {
- if(gcf == nil)
- addroot((Obj){frame->varp - i, i, 0});
- else if(i >= gcf->locals)
- addroot((Obj){frame->varp - gcf->locals, gcf->locals, 0});
+ // Use pointer information if known.
+ if(frame->varp > (byte*)frame->sp) {
+ locals = runtime·funcdata(f, FUNCDATA_GCLocals);
+ if(locals == nil) {
+ // No locals information, scan everything.
+ size = frame->varp - (byte*)frame->sp;
+ addroot((Obj){frame->varp - size, size, 0});
+ } else if(locals->n < 0) {
+ // Locals size information, scan just the
+ // locals.
+ size = -locals->n;
+ addroot((Obj){frame->varp - size, size, 0});
+ } else if(locals->n > 0) {
+ // Locals bitmap information, scan just the
+ // pointers in locals.
+ size = locals->n*PtrSize;
+ scanbitvector(frame->varp - size, locals);
+ }
}
// Scan arguments.
// Use pointer information if known.
- if(f->args > 0 && gcf != nil && gcf->nptrs > 0) {
- ap = frame->argp;
- nuintptr = f->args / sizeof(uintptr);
- for(i = 0; i < gcf->nptrs; i++) {
- w = gcf->ptrs[i];
- b = 1;
- j = nuintptr;
- if(j > 32)
- j = 32;
- for(; j > 0; j--) {
- if(w & b)
- addroot((Obj){ap, sizeof(uintptr), 0});
- b <<= 1;
- ap += sizeof(uintptr);
- }
- nuintptr -= 32;
- }
- } else
+ args = runtime·funcdata(f, FUNCDATA_GCArgs);
+ if(args != nil && args->n > 0)
+ scanbitvector(frame->argp, args);
+ else
addroot((Obj){frame->argp, frame->arglen, 0});
}