Skip to content

Commit

Permalink
runtime: make stack frames fixed size by modifying goproc/deferproc.
Browse files Browse the repository at this point in the history
Calls to goproc/deferproc used to push & pop two extra arguments,
the argument size and the function to call.  Now, we allocate space
for those arguments in the outargs section so we don't have to
modify the SP.

Defers now use the stack pointer (instead of the argument pointer)
to identify which frame they are associated with.

A followon CL might simplify funcspdelta and some of the stack
walking code.

Fixes issue golang#8641

Change-Id: I835ec2f42f0392c5dec7cb0fe6bba6f2aed1dad8
Reviewed-on: https://go-review.googlesource.com/1601
Reviewed-by: Russ Cox <[email protected]>
  • Loading branch information
randall77 committed Dec 23, 2014
1 parent 005ba4d commit 53c5226
Show file tree
Hide file tree
Showing 14 changed files with 149 additions and 151 deletions.
39 changes: 14 additions & 25 deletions src/cmd/5g/ggen.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,14 @@ ginscall(Node *f, int proc)
{
Prog *p;
Node n1, r, r1, con;
int32 extra;

if(f->type != T)
setmaxarg(f->type);
if(f->type != T) {
extra = 0;
if(proc == 1 || proc == 2)
extra = 2 * widthptr;
setmaxarg(f->type, extra);
}

switch(proc) {
default:
Expand Down Expand Up @@ -230,47 +235,29 @@ ginscall(Node *f, int proc)
case 1: // call in new proc (go)
case 2: // deferred call (defer)
regalloc(&r, types[tptr], N);
p = gins(AMOVW, N, &r);
p->from.type = D_OREG;
p->from.reg = REGSP;

nodconst(&con, types[TINT32], argsize(f->type));
gins(AMOVW, &con, &r);
p = gins(AMOVW, &r, N);
p->to.type = D_OREG;
p->to.reg = REGSP;
p->to.offset = -12;
p->scond |= C_WBIT;
p->to.offset = 4;

memset(&n1, 0, sizeof n1);
n1.op = OADDR;
n1.left = f;
gins(AMOVW, &n1, &r);

p = gins(AMOVW, &r, N);
p->to.type = D_OREG;
p->to.reg = REGSP;
p->to.offset = 8;

nodconst(&con, types[TINT32], argsize(f->type));
gins(AMOVW, &con, &r);
p = gins(AMOVW, &r, N);
p->to.type = D_OREG;
p->to.reg = REGSP;
p->to.offset = 4;
regfree(&r);

if(proc == 1)
ginscall(newproc, 0);
else
ginscall(deferproc, 0);

nodreg(&r, types[tptr], 1);
p = gins(AMOVW, N, N);
p->from.type = D_CONST;
p->from.reg = REGSP;
p->from.offset = 12;
p->to.reg = REGSP;
p->to.type = D_REG;

if(proc == 2) {
nodconst(&con, types[TINT32], 0);
p = gins(ACMP, &con, N);
Expand Down Expand Up @@ -330,9 +317,11 @@ cgen_callinter(Node *n, Node *res, int proc)
agen(i, &nodr); // REG = &inter

nodindreg(&nodsp, types[tptr], REGSP);
nodsp.xoffset = 4;
nodsp.xoffset = widthptr;
if(proc != 0)
nodsp.xoffset += 2 * widthptr; // leave room for size & fn
nodo.xoffset += widthptr;
cgen(&nodo, &nodsp); // 4(SP) = 4(REG) -- i.data
cgen(&nodo, &nodsp); // {4 or 12}(SP) = 4(REG) -- i.data

nodo.xoffset -= widthptr;
cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
Expand Down
58 changes: 36 additions & 22 deletions src/cmd/6g/ggen.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,16 @@ void
ginscall(Node *f, int proc)
{
Prog *p;
Node reg, con;
Node reg, stk;
Node r1;
int32 extra;

if(f->type != T)
setmaxarg(f->type);
if(f->type != T) {
extra = 0;
if(proc == 1 || proc == 2)
extra = 2 * widthptr;
setmaxarg(f->type, extra);
}

switch(proc) {
default:
Expand Down Expand Up @@ -224,35 +229,41 @@ ginscall(Node *f, int proc)

case 1: // call in new proc (go)
case 2: // deferred call (defer)
nodconst(&con, types[TINT64], argsize(f->type));
if(widthptr == 4) {
nodreg(&r1, types[TINT32], D_CX);
gmove(f, &r1);
nodreg(&reg, types[TINT64], D_CX);
nodconst(&r1, types[TINT64], 32);
gins(ASHLQ, &r1, &reg);
gins(AORQ, &con, &reg);
gins(APUSHQ, &reg, N);
memset(&stk, 0, sizeof(stk));
stk.op = OINDREG;
stk.val.u.reg = D_SP;
stk.xoffset = 0;

if(widthptr == 8) {
// size of arguments at 0(SP)
ginscon(AMOVQ, argsize(f->type), &stk);

// FuncVal* at 8(SP)
stk.xoffset = widthptr;
nodreg(&reg, types[TINT64], D_AX);
gmove(f, &reg);
gins(AMOVQ, &reg, &stk);
} else {
nodreg(&reg, types[TINT64], D_CX);
// size of arguments at 0(SP)
ginscon(AMOVL, argsize(f->type), &stk);

// FuncVal* at 4(SP)
stk.xoffset = widthptr;
nodreg(&reg, types[TINT32], D_AX);
gmove(f, &reg);
gins(APUSHQ, &reg, N);
gins(APUSHQ, &con, N);
gins(AMOVL, &reg, &stk);
}

if(proc == 1)
ginscall(newproc, 0);
else {
if(!hasdefer)
fatal("hasdefer=0 but has defer");
ginscall(deferproc, 0);
}
nodreg(&reg, types[TINT64], D_CX);
gins(APOPQ, N, &reg);
if(widthptr == 8)
gins(APOPQ, N, &reg);
if(proc == 2) {
nodreg(&reg, types[TINT64], D_AX);
gins(ATESTQ, &reg, &reg);
nodreg(&reg, types[TINT32], D_AX);
gins(ATESTL, &reg, &reg);
p = gbranch(AJEQ, T, +1);
cgen_ret(N);
patch(p, pc);
Expand Down Expand Up @@ -294,9 +305,12 @@ cgen_callinter(Node *n, Node *res, int proc)
igen(i, &nodi, res); // REG = &inter

nodindreg(&nodsp, types[tptr], D_SP);
nodsp.xoffset = 0;
if(proc != 0)
nodsp.xoffset += 2 * widthptr; // leave room for size & fn
nodi.type = types[tptr];
nodi.xoffset += widthptr;
cgen(&nodi, &nodsp); // 0(SP) = 8(REG) -- i.data
cgen(&nodi, &nodsp); // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data

regalloc(&nodo, types[tptr], res);
nodi.type = types[tptr];
Expand Down
37 changes: 26 additions & 11 deletions src/cmd/8g/ggen.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,15 @@ void
ginscall(Node *f, int proc)
{
Prog *p;
Node reg, r1, con;

if(f->type != T)
setmaxarg(f->type);
Node reg, r1, con, stk;
int32 extra;

if(f->type != T) {
extra = 0;
if(proc == 1 || proc == 2)
extra = 2 * widthptr;
setmaxarg(f->type, extra);
}

switch(proc) {
default:
Expand Down Expand Up @@ -284,18 +289,25 @@ ginscall(Node *f, int proc)

case 1: // call in new proc (go)
case 2: // deferred call (defer)
nodreg(&reg, types[TINT32], D_CX);
gins(APUSHL, f, N);
memset(&stk, 0, sizeof(stk));
stk.op = OINDREG;
stk.val.u.reg = D_SP;
stk.xoffset = 0;

// size of arguments at 0(SP)
nodconst(&con, types[TINT32], argsize(f->type));
gins(APUSHL, &con, N);
gins(AMOVL, &con, &stk);

// FuncVal* at 4(SP)
stk.xoffset = widthptr;
gins(AMOVL, f, &stk);

if(proc == 1)
ginscall(newproc, 0);
else
ginscall(deferproc, 0);
gins(APOPL, N, &reg);
gins(APOPL, N, &reg);
if(proc == 2) {
nodreg(&reg, types[TINT64], D_AX);
nodreg(&reg, types[TINT32], D_AX);
gins(ATESTL, &reg, &reg);
p = gbranch(AJEQ, T, +1);
cgen_ret(N);
Expand Down Expand Up @@ -338,9 +350,12 @@ cgen_callinter(Node *n, Node *res, int proc)
igen(i, &nodi, res); // REG = &inter

nodindreg(&nodsp, types[tptr], D_SP);
nodsp.xoffset = 0;
if(proc != 0)
nodsp.xoffset += 2 * widthptr; // leave room for size & fn
nodi.type = types[tptr];
nodi.xoffset += widthptr;
cgen(&nodi, &nodsp); // 0(SP) = 4(REG) -- i.data
cgen(&nodi, &nodsp); // {0 or 8}(SP) = 4(REG) -- i.data

regalloc(&nodo, types[tptr], res);
nodi.type = types[tptr];
Expand Down
25 changes: 10 additions & 15 deletions src/cmd/9g/ggen.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,14 @@ ginscall(Node *f, int proc)
Prog *p;
Node reg, con, reg2;
Node r1;
int32 extra;

if(f->type != T)
setmaxarg(f->type);
if(f->type != T) {
extra = 0;
if(proc == 1 || proc == 2)
extra = 2 * widthptr;
setmaxarg(f->type, extra);
}

switch(proc) {
default:
Expand Down Expand Up @@ -245,12 +250,6 @@ ginscall(Node *f, int proc)
nodreg(&reg2, types[TINT64], D_R0+4);
gmove(f, &reg);

p = gins(ASUB, N, N);
p->from.type = D_CONST;
p->from.offset = 3 * 8;
p->to.type = D_REG;
p->to.reg = REGSP;

gmove(&con, &reg2);
p = gins(AMOVW, &reg2, N);
p->to.type = D_OREG;
Expand All @@ -270,12 +269,6 @@ ginscall(Node *f, int proc)
ginscall(deferproc, 0);
}

p = gins(AADD, N, N);
p->from.type = D_CONST;
p->from.offset = 3 * 8;
p->to.type = D_REG;
p->to.reg = REGSP;

if(proc == 2) {
nodreg(&reg, types[TINT64], D_R0+3);
p = gins(ACMP, &reg, N);
Expand Down Expand Up @@ -324,9 +317,11 @@ cgen_callinter(Node *n, Node *res, int proc)

nodindreg(&nodsp, types[tptr], D_R0+REGSP);
nodsp.xoffset = widthptr;
if(proc != 0)
nodsp.xoffset += 2 * widthptr; // leave room for size & fn
nodi.type = types[tptr];
nodi.xoffset += widthptr;
cgen(&nodi, &nodsp); // 0(SP) = 8(REG) -- i.data
cgen(&nodi, &nodsp); // {8 or 24}(SP) = 8(REG) -- i.data

regalloc(&nodo, types[tptr], res);
nodi.type = types[tptr];
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/gc/go.h
Original file line number Diff line number Diff line change
Expand Up @@ -1418,7 +1418,7 @@ Node* cheapexpr(Node *n, NodeList **init);
Node* localexpr(Node *n, Type *t, NodeList **init);
void saveorignode(Node *n);
int32 setlineno(Node *n);
void setmaxarg(Type *t);
void setmaxarg(Type *t, int32 extra);
Type* shallow(Type *t);
int simsimtype(Type *t);
void smagic(Magic *m);
Expand Down
7 changes: 5 additions & 2 deletions src/cmd/gc/subr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2115,14 +2115,17 @@ localexpr(Node *n, Type *t, NodeList **init)
}

void
setmaxarg(Type *t)
setmaxarg(Type *t, int32 extra)
{
int64 w;

dowidth(t);
w = t->argwid;
if(t->argwid >= MAXWIDTH)
if(w >= MAXWIDTH)
fatal("bad argwid %T", t);
w += extra;
if(w >= MAXWIDTH)
fatal("bad argwid %d + %T", extra, t);
if(w > maxarg)
maxarg = w;
}
Expand Down
33 changes: 33 additions & 0 deletions src/cmd/gc/walk.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,35 @@ paramoutheap(Node *fn)
return 0;
}

// adds "adjust" to all the argument locations for the call n.
// n must be a defer or go node that has already been walked.
static void
adjustargs(Node *n, int adjust)
{
Node *callfunc, *arg, *lhs;
NodeList *args;

callfunc = n->left;
for(args = callfunc->list; args != 0; args = args->next) {
arg = args->n;
if(arg->op != OAS)
yyerror("call arg not assignment");
lhs = arg->left;
if(lhs->op == ONAME) {
// This is a temporary introduced by reorder1.
// The real store to the stack appears later in the arg list.
continue;
}
if(lhs->op != OINDREG) {
yyerror("call argument store does not use OINDREG");
}
// can't really check this in machine-indep code.
//if(lhs->val.u.reg != D_SP)
// yyerror("call arg assign not indreg(SP)");
lhs->xoffset += adjust;
}
}

void
walkstmt(Node **np)
{
Expand Down Expand Up @@ -237,6 +266,8 @@ walkstmt(Node **np)
walkexpr(&n->left, &n->ninit);
break;
}
// make room for size & fn arguments.
adjustargs(n, 2 * widthptr);
break;

case OFOR:
Expand Down Expand Up @@ -270,6 +301,8 @@ walkstmt(Node **np)
walkexpr(&n->left, &n->ninit);
break;
}
// make room for size & fn arguments.
adjustargs(n, 2 * widthptr);
break;

case ORETURN:
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/heapdump.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ func dumpgoroutine(gp *g) {
dumpint(tagDefer)
dumpint(uint64(uintptr(unsafe.Pointer(d))))
dumpint(uint64(uintptr(unsafe.Pointer(gp))))
dumpint(uint64(d.argp))
dumpint(uint64(d.sp))
dumpint(uint64(d.pc))
dumpint(uint64(uintptr(unsafe.Pointer(d.fn))))
dumpint(uint64(uintptr(unsafe.Pointer(d.fn.fn))))
Expand Down
Loading

0 comments on commit 53c5226

Please sign in to comment.