]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cc, cmd/gc, runtime: emit bitmaps for scanning locals.
authorCarl Shapiro <cshapiro@google.com>
Wed, 7 Aug 2013 19:47:01 +0000 (12:47 -0700)
committerCarl Shapiro <cshapiro@google.com>
Wed, 7 Aug 2013 19:47:01 +0000 (12:47 -0700)
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

src/cmd/cc/pgen.c
src/cmd/gc/pgen.c
src/pkg/runtime/funcdata.h
src/pkg/runtime/mgc0.c

index a6b0f947e1eeb9a49dfd2f0286ab0044b3d9f149..29ab49c42eedfa8b8b58778996f99a3ef269c897 100644 (file)
@@ -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
index 6b8fe4676df77afc362566c34273140f738a0dd6..8b268a218a5ccc6d041ff527f9a237fb43343032 100644 (file)
@@ -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,
index f12bf49fb181257b08445187e3370c4f8f65a71c..166263ef9070cf322188e275528d26ee8e5c8d24 100644 (file)
@@ -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
index be0f81879e47e580aa76ee772ac7b33e5f65ce4b..abf5df10c1115fc5cd2f33357aa9212728465a58 100644 (file)
@@ -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});
 }