diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index bc39912ea3..caaa3e246f 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -124,6 +124,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), p3); + + // continue with original code. + gins(ANOP, N, N)->link = p2; + pc = P; +} + void gused(Node *n) { diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index ae6ae57651..66dac11859 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -120,6 +120,41 @@ newplist(void) return pl; } +void +clearstk(void) +{ + Plist *pl; + Prog *p1, *p2; + Node sp, di, cx, con; + + 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); + gins(AREP, N, N); + gins(ASTOSQ, N, N); + + // continue with original code. + gins(ANOP, N, N)->link = p2; + pc = P; +} + void gused(Node *n) { diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c index 6bcc3eed84..d0c7310251 100644 --- a/src/cmd/8g/gsubr.c +++ b/src/cmd/8g/gsubr.c @@ -122,6 +122,41 @@ newplist(void) return pl; } +void +clearstk(void) +{ + Plist *pl; + Prog *p1, *p2; + Node sp, di, cx, 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 + 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); + gins(AREP, N, N); + gins(ASTOSL, N, N); + + // continue with original code. + gins(ANOP, N, N)->link = p2; + pc = P; +} + void gused(Node *n) { diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 83be82f92f..335d056a06 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -1241,9 +1241,14 @@ funccompile(Node *n, int isclosure) stksize = 0; dclcontext = PAUTO; funcdepth = n->funcdepth + 1; + hasgoto = 0; compile(n); + if(hasgoto) + clearstk(); curfn = nil; funcdepth = 0; dclcontext = PEXTERN; } + + diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index feb55e9051..ad7b65b306 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -209,6 +209,7 @@ gen(Node *n) break; case OGOTO: + hasgoto = 1; newlab(OGOTO, n, N); gjmp(P); break; diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 2dfcb1669b..a689d603d1 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -1257,3 +1257,6 @@ void zhist(Biobuf *b, int line, vlong offset); void zname(Biobuf *b, Sym *s, int t); void data(void); void text(void); + +EXTERN int hasgoto; +void clearstk(void); diff --git a/test/fixedbugs/bug344.go b/test/fixedbugs/bug344.go new file mode 100644 index 0000000000..2a20dcf6ff --- /dev/null +++ b/test/fixedbugs/bug344.go @@ -0,0 +1,22 @@ +// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug344 + +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +func main() { + // invalid use of goto. + // do whatever you like, just don't crash. + i := 42 + a := []*int{&i, &i, &i, &i} + x := a[0] + goto start + for _, x = range a { + start: + fmt.Sprint(*x) + } +}