Commit 73c93a40 authored by Carl Shapiro's avatar Carl Shapiro

cmd/cc, cmd/gc, runtime: emit bitmaps for scanning locals.

Previously, all word aligned locations in the local variables
area were scanned as conservative roots.  With this change, a
bitmap is generated describing the locations of pointer values
in local variables.

With this change the argument bitmap information has been
changed to only store information about arguments.  The locals
member, has been removed.  In its place, the bitmap data for
local variables is now used to store the size of locals.  If
the size is negative, the magnitude indicates the size of the
local variables area.

R=rsc
CC=golang-dev
https://golang.org/cl/12328044
parent 0273dc13
......@@ -78,9 +78,9 @@ void
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;
......@@ -116,7 +116,17 @@ codgen(Node *n, Node *nn)
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
......@@ -165,11 +175,15 @@ codgen(Node *n, Node *nn)
// 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
......
......@@ -9,22 +9,22 @@
#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");
......@@ -93,13 +93,21 @@ compile(Node *fn)
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));
......@@ -159,37 +167,29 @@ compile(Node *fn)
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)
{
......@@ -296,13 +296,15 @@ walktype(Type *type, 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);
......@@ -314,11 +316,42 @@ pointermap(Sym *gcsym, int off, Node *fn)
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,
......
......@@ -9,7 +9,8 @@
#define PCDATA_ArgSize 0 /* argument size at CALL instruction */
#define FUNCDATA_GC 0 /* garbage collector block */
#define FUNCDATA_GCArgs 0 /* garbage collector blocks */
#define FUNCDATA_GCLocals 1
// To be used in assembly.
#define ARGSIZE(n) PCDATA $PCDATA_ArgSize, $n
......
......@@ -1387,56 +1387,74 @@ addroot(Obj obj)
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});
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment