diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index 288c38588d..8946a9e51e 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -9,9 +9,15 @@ #include "gg.h" #include "opt.h" +static Prog* appendp(Prog*, int, int, int, int32, int, int, int32); + void -defframe(Prog *ptxt) +defframe(Prog *ptxt, Bvec *bv) { + int i, first; + uint32 frame; + Prog *p, *p1; + // fill in argument size ptxt->to.type = D_CONST2; ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr); @@ -19,8 +25,60 @@ defframe(Prog *ptxt) // fill in final stack size if(stksize > maxstksize) maxstksize = stksize; - ptxt->to.offset = rnd(maxstksize+maxarg, widthptr); + frame = rnd(maxstksize+maxarg, widthptr); + ptxt->to.offset = frame; maxstksize = 0; + + // insert code to clear pointered part of the frame, + // so that garbage collector only sees initialized values + // when it looks for pointers. + p = ptxt; + while(p->link->as == AFUNCDATA || p->link->as == APCDATA || p->link->as == ATYPE) + p = p->link; + if(stkptrsize >= 8*widthptr) { + p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0); + p = appendp(p, AADD, D_CONST, NREG, 4+frame-stkptrsize, D_REG, 1, 0); + p->reg = REGSP; + p = appendp(p, AADD, D_CONST, NREG, stkptrsize, D_REG, 2, 0); + p->reg = 1; + p1 = p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4); + p->scond |= C_PBIT; + p = appendp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0); + p->reg = 2; + p = appendp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0); + patch(p, p1); + } else { + first = 1; + for(i=0; ias = as; + q->lineno = p->lineno; + q->from.type = ftype; + q->from.reg = freg; + q->from.offset = foffset; + q->to.type = ttype; + q->to.reg = treg; + q->to.offset = toffset; + q->link = p->link; + p->link = q; + return q; } // Sweep the prog list to mark any used nodes. diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index ec558f2e61..b0ef88cb95 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -9,15 +9,56 @@ #include "gg.h" #include "opt.h" +static Prog* appendp(Prog*, int, int, vlong, int, vlong); + void -defframe(Prog *ptxt) +defframe(Prog *ptxt, Bvec *bv) { + int i; + uint32 frame; + Prog *p; + // fill in argument size ptxt->to.offset = rnd(curfn->type->argwid, widthptr); // fill in final stack size ptxt->to.offset <<= 32; - ptxt->to.offset |= rnd(stksize+maxarg, widthptr); + frame = rnd(stksize+maxarg, widthptr); + ptxt->to.offset |= frame; + + // insert code to clear pointered part of the frame, + // so that garbage collector only sees initialized values + // when it looks for pointers. + p = ptxt; + if(stkptrsize >= 8*widthptr) { + p = appendp(p, AMOVQ, D_CONST, 0, D_AX, 0); + p = appendp(p, AMOVQ, D_CONST, stkptrsize/widthptr, D_CX, 0); + p = appendp(p, ALEAQ, D_SP+D_INDIR, frame-stkptrsize, D_DI, 0); + p = appendp(p, AREP, D_NONE, 0, D_NONE, 0); + appendp(p, ASTOSQ, D_NONE, 0, D_NONE, 0); + } else { + for(i=0; ias = as; + q->lineno = p->lineno; + q->from.type = ftype; + q->from.offset = foffset; + q->to.type = ttype; + q->to.offset = toffset; + q->link = p->link; + p->link = q; + return q; } // Sweep the prog list to mark any used nodes. diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index 1677d9529b..cbe7a5e55e 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -9,17 +9,58 @@ #include "gg.h" #include "opt.h" +static Prog* appendp(Prog*, int, int, int32, int, int32); + void -defframe(Prog *ptxt) +defframe(Prog *ptxt, Bvec *bv) { + uint32 frame; + Prog *p; + int i; + // fill in argument size ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr); // fill in final stack size if(stksize > maxstksize) maxstksize = stksize; - ptxt->to.offset = rnd(maxstksize+maxarg, widthptr); + frame = rnd(maxstksize+maxarg, widthptr); + ptxt->to.offset = frame; maxstksize = 0; + + // insert code to clear pointered part of the frame, + // so that garbage collector only sees initialized values + // when it looks for pointers. + p = ptxt; + if(stkptrsize >= 8*widthptr) { + p = appendp(p, AMOVL, D_CONST, 0, D_AX, 0); + p = appendp(p, AMOVL, D_CONST, stkptrsize/widthptr, D_CX, 0); + p = appendp(p, ALEAL, D_SP+D_INDIR, frame-stkptrsize, D_DI, 0); + p = appendp(p, AREP, D_NONE, 0, D_NONE, 0); + appendp(p, ASTOSL, D_NONE, 0, D_NONE, 0); + } else { + for(i=0; ias = as; + q->lineno = p->lineno; + q->from.type = ftype; + q->from.offset = foffset; + q->to.type = ttype; + q->to.offset = toffset; + q->link = p->link; + p->link = q; + return q; } // Sweep the prog list to mark any used nodes. diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 05c864a1c5..6679fa855d 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -1458,7 +1458,7 @@ void cgen_callinter(Node *n, Node *res, int proc); void cgen_ret(Node *n); void clearfat(Node *n); void compile(Node*); -void defframe(Prog*); +void defframe(Prog*, Bvec*); int dgostringptr(Sym*, int off, char *str); int dgostrlitptr(Sym*, int off, Strlit*); int dstringptr(Sym *s, int off, char *str); diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c index 6595abce42..d465ab5c3c 100644 --- a/src/cmd/gc/pgen.c +++ b/src/cmd/gc/pgen.c @@ -12,11 +12,12 @@ enum { BitsPerPointer = 2 }; static void allocauto(Prog* p); static void dumpgcargs(Node*, Sym*); -static void dumpgclocals(Node*, Sym*); +static Bvec* dumpgclocals(Node*, Sym*); void compile(Node *fn) { + Bvec *bv; Plist *pl; Node nod1, *n, *gcargsnod, *gclocalsnod; Prog *ptxt, *p, *p1; @@ -179,15 +180,16 @@ compile(Node *fn) goto ret; } - defframe(ptxt); + // Emit garbage collection symbols. + dumpgcargs(fn, gcargssym); + bv = dumpgclocals(curfn, gclocalssym); + + defframe(ptxt, bv); + free(bv); if(0) frame(0); - // Emit garbage collection symbols. - dumpgcargs(fn, gcargssym); - dumpgclocals(curfn, gclocalssym); - ret: lineno = lno; } @@ -329,8 +331,8 @@ dumpgcargs(Node *fn, Sym *sym) // 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 +// the provided symbol. Returns the vector for use and freeing by caller. +static Bvec* dumpgclocals(Node* fn, Sym *sym) { Bvec *bv; @@ -354,8 +356,8 @@ dumpgclocals(Node* fn, Sym *sym) for(i = 0; i < bv->n; i += 32) { off = duint32(sym, off, bv->b[i/32]); } - free(bv); ggloblsym(sym, off, 0, 1); + return bv; } // Sort the list of stack variables. Autos after anything else, diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 033b041f3c..7e5f678028 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -2309,7 +2309,9 @@ paramstoheap(Type **argin, int out) v = t->nname; if(v && v->sym && v->sym->name[0] == '~') v = N; - if(v == N && out && hasdefer) { + // The garbage collector assumes results are always live, + // so zero them always (1 ||). + if(out && (1 || (v == N && hasdefer))) { // Defer might stop a panic and show the // return values as they exist at the time of panic. // Make sure to zero them on entry to the function.