mirror of
https://github.com/golang/go
synced 2024-10-03 06:21:21 -06:00
cmd/gc: add GOEXPERIMENT=zerostack to clear stack on function entry
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
This commit is contained in:
parent
5a2c275be1
commit
b7603cfc2c
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -41,6 +41,7 @@ static struct {
|
||||
} exper[] = {
|
||||
// {"rune32", &rune32},
|
||||
{"fieldtrack", &fieldtrack_enabled},
|
||||
{"zerostack", &zerostack_enabled},
|
||||
{nil, nil},
|
||||
};
|
||||
|
||||
|
@ -141,6 +141,9 @@ compile(Node *fn)
|
||||
if(0)
|
||||
frame(0);
|
||||
|
||||
if(zerostack_enabled)
|
||||
clearstk();
|
||||
|
||||
ret:
|
||||
lineno = lno;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user