]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: add GOEXPERIMENT=zerostack to clear stack on function entry
authorRuss Cox <rsc@golang.org>
Mon, 17 Dec 2012 19:32:26 +0000 (14:32 -0500)
committerRuss Cox <rsc@golang.org>
Mon, 17 Dec 2012 19:32:26 +0000 (14:32 -0500)
This is expensive but it might be useful in cases where
people are suffering from false positives during garbage
collection and are willing to trade the CPU time for getting
rid of the false positives.

On the other hand it only eliminates false positives caused
by other function calls, not false positives caused by dead
temporaries stored in the current function call.

The 5g/6g/8g changes were pulled out of the history, from
the last time we needed to do this (to work around a goto bug).
The code in go.h, lex.c, pgen.c is new but tiny.

R=ken2
CC=golang-dev
https://golang.org/cl/6938073

src/cmd/5g/gsubr.c
src/cmd/6g/gsubr.c
src/cmd/8g/gsubr.c
src/cmd/gc/go.h
src/cmd/gc/lex.c
src/cmd/gc/pgen.c

index f023b269c81084a3abe2c1eeb76e4fd91d97c648..3d1c68f80424ddc0f9ef553216168c1088c40dd4 100644 (file)
@@ -174,6 +174,64 @@ newplist(void)
        return pl;
 }
 
+void
+clearstk(void)
+{
+       Plist *pl;
+       Prog *p, *p1, *p2, *p3;
+       Node dst, end, zero, con;
+
+       if(plast->firstpc->to.offset <= 0)
+               return;
+
+       // reestablish context for inserting code
+       // at beginning of function.
+       pl = plast;
+       p1 = pl->firstpc;
+       p2 = p1->link;
+       pc = mal(sizeof(*pc));
+       clearp(pc);
+       p1->link = pc;
+       
+       // zero stack frame
+
+       // MOVW $4(SP), R1
+       nodreg(&dst, types[tptr], 1);
+       p = gins(AMOVW, N, &dst);
+       p->from.type = D_CONST;
+       p->from.reg = REGSP;
+       p->from.offset = 4;
+
+       // MOVW $n(R1), R2
+       nodreg(&end, types[tptr], 2);
+       p = gins(AMOVW, N, &end);
+       p->from.type = D_CONST;
+       p->from.reg = 1;
+       p->from.offset = p1->to.offset;
+       
+       // MOVW $0, R3
+       nodreg(&zero, types[TUINT32], 3);
+       nodconst(&con, types[TUINT32], 0);
+       gmove(&con, &zero);
+
+       // L:
+       //      MOVW.P R3, 0(R1) +4
+       //      CMP R1, R2
+       //      BNE L
+       p = gins(AMOVW, &zero, &dst);
+       p->to.type = D_OREG;
+       p->to.offset = 4;
+       p->scond |= C_PBIT;
+       p3 = p;
+       p = gins(ACMP, &dst, N);
+       raddr(&end, p);
+       patch(gbranch(ABNE, T, 0), p3);
+
+       // continue with original code.
+       gins(ANOP, N, N)->link = p2;
+       pc = P;
+}      
+
 void
 gused(Node *n)
 {
index 65d5ad786fa5413130f664d80ce91df1f50c54dd..cdc5fdae2e0bcd1237e5633748f34549861ad7b4 100644 (file)
@@ -172,6 +172,44 @@ newplist(void)
        return pl;
 }
 
+void
+clearstk(void)
+{
+       Plist *pl;
+       Prog *p1, *p2;
+       Node sp, di, cx, con, ax;
+
+       if((uint32)plast->firstpc->to.offset <= 0)
+               return;
+
+       // reestablish context for inserting code
+       // at beginning of function.
+       pl = plast;
+       p1 = pl->firstpc;
+       p2 = p1->link;
+       pc = mal(sizeof(*pc));
+       clearp(pc);
+       p1->link = pc;
+       
+       // zero stack frame
+       nodreg(&sp, types[tptr], D_SP);
+       nodreg(&di, types[tptr], D_DI);
+       nodreg(&cx, types[TUINT64], D_CX);
+       nodconst(&con, types[TUINT64], (uint32)p1->to.offset / widthptr);
+       gins(ACLD, N, N);
+       gins(AMOVQ, &sp, &di);
+       gins(AMOVQ, &con, &cx);
+       nodconst(&con, types[TUINT64], 0);
+       nodreg(&ax, types[TUINT64], D_AX);
+       gins(AMOVQ, &con, &ax);
+       gins(AREP, N, N);
+       gins(ASTOSQ, N, N);
+
+       // continue with original code.
+       gins(ANOP, N, N)->link = p2;
+       pc = P;
+}      
+
 void
 gused(Node *n)
 {
index dbea45a20191e621233d6650f6e8b95882e27d93..93cea2146982593414d181d1e8a5fb5e5ae545f6 100644 (file)
@@ -173,6 +173,44 @@ newplist(void)
        return pl;
 }
 
+void
+clearstk(void)
+{
+       Plist *pl;
+       Prog *p1, *p2;
+       Node sp, di, cx, con, ax;
+
+       if(plast->firstpc->to.offset <= 0)
+               return;
+
+       // reestablish context for inserting code
+       // at beginning of function.
+       pl = plast;
+       p1 = pl->firstpc;
+       p2 = p1->link;
+       pc = mal(sizeof(*pc));
+       clearp(pc);
+       p1->link = pc;
+       
+       // zero stack frame
+       nodreg(&sp, types[tptr], D_SP);
+       nodreg(&di, types[tptr], D_DI);
+       nodreg(&cx, types[TUINT32], D_CX);
+       nodconst(&con, types[TUINT32], p1->to.offset / widthptr);
+       gins(ACLD, N, N);
+       gins(AMOVL, &sp, &di);
+       gins(AMOVL, &con, &cx);
+       nodconst(&con, types[TUINT32], 0);
+       nodreg(&ax, types[TUINT32], D_AX);
+       gins(AMOVL, &con, &ax);
+       gins(AREP, N, N);
+       gins(ASTOSL, N, N);
+
+       // continue with original code.
+       gins(ANOP, N, N)->link = p2;
+       pc = P;
+}      
+
 void
 gused(Node *n)
 {
index 36bc4b2954744c7397ebc9b1798eca59a977ac40..42319578a834fe6f09f798fcd58642179b5404b8 100644 (file)
@@ -937,6 +937,7 @@ EXTERN      int     funcdepth;
 EXTERN int     typecheckok;
 EXTERN int     compiling_runtime;
 EXTERN int     compiling_wrappers;
+EXTERN int     zerostack_enabled;
 
 EXTERN int     nointerface;
 EXTERN int     fieldtrack_enabled;
@@ -1092,6 +1093,7 @@ void      genlist(NodeList *l);
 Node*  sysfunc(char *name);
 void   tempname(Node *n, Type *t);
 Node*  temp(Type*);
+void   clearstk(void);
 
 /*
  *     init.c
index eabeaeb646971e7c7d2c2be2af83d65f3d934e76..8d6487dea7d8cc3a4d1e8b91652e5f731f0971f2 100644 (file)
@@ -41,6 +41,7 @@ static struct {
 } exper[] = {
 //     {"rune32", &rune32},
        {"fieldtrack", &fieldtrack_enabled},
+       {"zerostack", &zerostack_enabled},
        {nil, nil},
 };
 
index 7be254fff173e2cab585e14164cf591afb706620..e2cad1439865da7fda020018d6e452b1b24dbc9b 100644 (file)
@@ -141,6 +141,9 @@ compile(Node *fn)
        if(0)
                frame(0);
 
+       if(zerostack_enabled)
+               clearstk();
+
 ret:
        lineno = lno;
 }