Commit 391425ae authored by Russ Cox's avatar Russ Cox

if take address of local, move to heap.

heuristic to not print bogus strings.
fix one error message format.

R=ken
OCL=23849
CL=23851
parent 699721a0
...@@ -48,6 +48,11 @@ cgen(Node *n, Node *res) ...@@ -48,6 +48,11 @@ cgen(Node *n, Node *res)
if(n->ullman > res->ullman) { if(n->ullman > res->ullman) {
regalloc(&n1, n->type, res); regalloc(&n1, n->type, res);
cgen(n, &n1); cgen(n, &n1);
if(n1.ullman > res->ullman) {
dump("n1", &n1);
dump("res", res);
fatal("loop in cgen");
}
cgen(&n1, res); cgen(&n1, res);
regfree(&n1); regfree(&n1);
goto ret; goto ret;
...@@ -198,6 +203,7 @@ cgen(Node *n, Node *res) ...@@ -198,6 +203,7 @@ cgen(Node *n, Node *res)
case ODOTPTR: case ODOTPTR:
case OINDEX: case OINDEX:
case OIND: case OIND:
case ONAME: // PHEAP var
igen(n, &n1, res); igen(n, &n1, res);
gmove(&n1, res); gmove(&n1, res);
regfree(&n1); regfree(&n1);
...@@ -517,6 +523,17 @@ agen(Node *n, Node *res) ...@@ -517,6 +523,17 @@ agen(Node *n, Node *res)
regfree(&n3); regfree(&n3);
break; break;
case ONAME:
// should only get here for heap vars
if(!(n->class & PHEAP))
fatal("agen: bad ONAME class %#x", n->class);
cgen(n->heapaddr, res);
if(n->xoffset != 0) {
nodconst(&n1, types[TINT64], n->xoffset);
gins(optoas(OADD, types[tptr]), &n1, res);
}
break;
case OIND: case OIND:
cgen(nl, res); cgen(nl, res);
break; break;
......
...@@ -99,6 +99,7 @@ if(throwreturn == N) { ...@@ -99,6 +99,7 @@ if(throwreturn == N) {
// inarggen(); // inarggen();
ginit(); ginit();
gen(curfn->enter, L);
gen(curfn->nbody, L); gen(curfn->nbody, L);
gclean(); gclean();
checklabels(); checklabels();
...@@ -151,6 +152,8 @@ allocparams(void) ...@@ -151,6 +152,8 @@ allocparams(void)
dowidth(n->type); dowidth(n->type);
w = n->type->width; w = n->type->width;
if(n->class & PHEAP)
w = widthptr;
stksize += w; stksize += w;
stksize = rnd(stksize, w); stksize = rnd(stksize, w);
...@@ -345,6 +348,10 @@ loop: ...@@ -345,6 +348,10 @@ loop:
cgen_asop(n); cgen_asop(n);
break; break;
case ODCL:
cgen_dcl(n->left);
break;
case OAS: case OAS:
cgen_as(n->left, n->right); cgen_as(n->left, n->right);
break; break;
...@@ -1114,6 +1121,26 @@ ret: ...@@ -1114,6 +1121,26 @@ ret:
; ;
} }
/*
* generate declaration.
* nothing to do for on-stack automatics,
* but might have to allocate heap copy
* for escaped variables.
*/
void
cgen_dcl(Node *n)
{
if(debug['g'])
dump("\ncgen-dcl", n);
if(n->op != ONAME) {
dump("cgen_dcl", n);
fatal("cgen_dcl");
}
if(!(n->class & PHEAP))
return;
cgen_as(n->heapaddr, n->alloc);
}
/* /*
* generate assignment: * generate assignment:
* nl = nr * nl = nr
...@@ -1130,6 +1157,11 @@ cgen_as(Node *nl, Node *nr) ...@@ -1130,6 +1157,11 @@ cgen_as(Node *nl, Node *nr)
if(nl == N) if(nl == N)
return; return;
if(debug['g']) {
dump("cgen_as", nl);
dump("cgen_as = ", nr);
}
iszer = 0; iszer = 0;
if(nr == N || isnil(nr)) { if(nr == N || isnil(nr)) {
if(nl->op == OLIST) { if(nl->op == OLIST) {
......
...@@ -158,6 +158,7 @@ void cgen_callret(Node*, Node*); ...@@ -158,6 +158,7 @@ void cgen_callret(Node*, Node*);
void cgen_div(int, Node*, Node*, Node*); void cgen_div(int, Node*, Node*, Node*);
void cgen_bmul(int, Node*, Node*, Node*); void cgen_bmul(int, Node*, Node*, Node*);
void cgen_shift(int, Node*, Node*, Node*); void cgen_shift(int, Node*, Node*, Node*);
void cgen_dcl(Node*);
void genpanic(void); void genpanic(void);
int needconvert(Type*, Type*); int needconvert(Type*, Type*);
void genconv(Type*, Type*); void genconv(Type*, Type*);
......
...@@ -547,6 +547,7 @@ gmove(Node *f, Node *t) ...@@ -547,6 +547,7 @@ gmove(Node *f, Node *t)
break; break;
case PAUTO: case PAUTO:
case PPARAM: case PPARAM:
case PPARAMOUT:
break; break;
} }
break; break;
...@@ -1046,6 +1047,15 @@ naddr(Node *n, Addr *a) ...@@ -1046,6 +1047,15 @@ naddr(Node *n, Addr *a)
a->offset = n->xoffset; a->offset = n->xoffset;
break; break;
case OPARAM:
// n->left is PHEAP ONAME for stack parameter.
// compute address of actual parameter on stack.
a->etype = n->left->type->etype;
a->offset = n->xoffset;
a->sym = n->left->sym;
a->type = D_PARAM;
break;
case ONAME: case ONAME:
a->etype = 0; a->etype = 0;
if(n->type != T) if(n->type != T)
...@@ -1071,6 +1081,7 @@ naddr(Node *n, Addr *a) ...@@ -1071,6 +1081,7 @@ naddr(Node *n, Addr *a)
a->type = D_AUTO; a->type = D_AUTO;
break; break;
case PPARAM: case PPARAM:
case PPARAMOUT:
a->type = D_PARAM; a->type = D_PARAM;
break; break;
} }
...@@ -1749,6 +1760,7 @@ tempname(Node *n, Type *t) ...@@ -1749,6 +1760,7 @@ tempname(Node *n, Type *t)
n->class = PAUTO; n->class = PAUTO;
n->addable = 1; n->addable = 1;
n->ullman = 1; n->ullman = 1;
n->noescape = 1;
dowidth(t); dowidth(t);
w = t->width; w = t->width;
......
...@@ -36,6 +36,7 @@ dodclvar(Node *n, Type *t) ...@@ -36,6 +36,7 @@ dodclvar(Node *n, Type *t)
addvar(n, t, dclcontext); addvar(n, t, dclcontext);
autoexport(n->sym); autoexport(n->sym);
addtop = list(addtop, nod(ODCL, n, N));
} }
void void
...@@ -434,7 +435,7 @@ funcargs(Type *ft) ...@@ -434,7 +435,7 @@ funcargs(Type *ft)
if(t->nname != N) if(t->nname != N)
t->nname->xoffset = t->width; t->nname->xoffset = t->width;
if(t->nname != N) { if(t->nname != N) {
addvar(t->nname, t->type, PPARAM); addvar(t->nname, t->type, PPARAMOUT);
all |= 1; all |= 1;
} else } else
all |= 2; all |= 2;
......
...@@ -180,12 +180,13 @@ struct Node ...@@ -180,12 +180,13 @@ struct Node
uchar addable; // type of addressability - 0 is not addressable uchar addable; // type of addressability - 0 is not addressable
uchar trecur; // to detect loops uchar trecur; // to detect loops
uchar etype; // op for OASOP, etype for OTYPE, exclam for export uchar etype; // op for OASOP, etype for OTYPE, exclam for export
uchar class; // PPARAM, PAUTO, PEXTERN uchar class; // PPARAM, PAUTO, PEXTERN, etc
uchar method; // OCALLMETH name uchar method; // OCALLMETH name
uchar iota; // OLITERAL made from iota uchar iota; // OLITERAL made from iota
uchar embedded; // ODCLFIELD embedded type uchar embedded; // ODCLFIELD embedded type
uchar colas; // OAS resulting from := uchar colas; // OAS resulting from :=
uchar diag; // already printed error about this uchar diag; // already printed error about this
uchar noescape; // ONAME never move to heap
// most nodes // most nodes
Node* left; Node* left;
...@@ -206,10 +207,17 @@ struct Node ...@@ -206,10 +207,17 @@ struct Node
// func // func
Node* nname; Node* nname;
Node* enter;
Node* exit;
// OLITERAL/OREGISTER // OLITERAL/OREGISTER
Val val; Val val;
// ONAME func param with PHEAP
Node* heapaddr; // temp holding heap address of param
Node* stackparam; // OPARAM node referring to stack copy of param
Node* alloc; // allocation call
Sym* osym; // import Sym* osym; // import
Sym* psym; // import Sym* psym; // import
Sym* sym; // various Sym* sym; // various
...@@ -287,7 +295,7 @@ enum ...@@ -287,7 +295,7 @@ enum
OTYPE, OCONST, OVAR, OIMPORT, OTYPE, OCONST, OVAR, OIMPORT,
ONAME, ONONAME, ONAME, ONONAME, ODCL,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
ODCLFUNC, ODCLFIELD, ODCLARG, ODCLFUNC, ODCLFIELD, ODCLARG,
OLIST, OCMP, OPTR, OARRAY, ORANGE, OLIST, OCMP, OPTR, OARRAY, ORANGE,
...@@ -312,7 +320,7 @@ enum ...@@ -312,7 +320,7 @@ enum
OINDEX, OSLICE, OINDEX, OSLICE,
ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV, ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV,
OLITERAL, OREGISTER, OINDREG, OLITERAL, OREGISTER, OINDREG,
OCONV, OCOMP, OKEY, OCONV, OCOMP, OKEY, OPARAM,
OBAD, OBAD,
OEXTEND, // 6g internal OEXTEND, // 6g internal
...@@ -405,6 +413,9 @@ enum ...@@ -405,6 +413,9 @@ enum
PEXTERN, // declaration context PEXTERN, // declaration context
PAUTO, PAUTO,
PPARAM, PPARAM,
PPARAMOUT,
PHEAP = 1<<7,
}; };
enum enum
...@@ -654,6 +665,7 @@ Node* treecopy(Node*); ...@@ -654,6 +665,7 @@ Node* treecopy(Node*);
int isselect(Node*); int isselect(Node*);
void tempname(Node*, Type*); void tempname(Node*, Type*);
int iscomposite(Type*); int iscomposite(Type*);
Node* callnew(Type*);
Type** getthis(Type*); Type** getthis(Type*);
Type** getoutarg(Type*); Type** getoutarg(Type*);
...@@ -812,11 +824,13 @@ Node* reorder1(Node*); ...@@ -812,11 +824,13 @@ Node* reorder1(Node*);
Node* reorder2(Node*); Node* reorder2(Node*);
Node* reorder3(Node*); Node* reorder3(Node*);
Node* reorder4(Node*); Node* reorder4(Node*);
Node* structlit(Node*); Node* structlit(Node*, Node*);
Node* arraylit(Node*); Node* arraylit(Node*);
Node* maplit(Node*); Node* maplit(Node*);
Node* selectas(Node*, Node*); Node* selectas(Node*, Node*);
Node* old2new(Node*, Type*); Node* old2new(Node*, Type*);
void addrescapes(Node*);
void heapmoves(void);
/* /*
* const.c * const.c
......
...@@ -278,6 +278,7 @@ Avardcl: ...@@ -278,6 +278,7 @@ Avardcl:
dodclvar($$, $2); dodclvar($$, $2);
$$ = nod(OAS, $$, N); $$ = nod(OAS, $$, N);
addtotop($$);
} }
Bvardcl: Bvardcl:
...@@ -287,6 +288,7 @@ Bvardcl: ...@@ -287,6 +288,7 @@ Bvardcl:
dodclvar($$, $2); dodclvar($$, $2);
$$ = nod(OAS, $$, N); $$ = nod(OAS, $$, N);
addtotop($$);
} }
| new_name_list_r type '=' expr_list | new_name_list_r type '=' expr_list
{ {
...@@ -478,6 +480,7 @@ complex_stmt: ...@@ -478,6 +480,7 @@ complex_stmt:
poptodcl(); poptodcl();
$$ = nod(OAS, selectas($2,$4), $4); $$ = nod(OAS, selectas($2,$4), $4);
$$ = nod(OXCASE, $$, N); $$ = nod(OXCASE, $$, N);
addtotop($$);
} }
| LDEFAULT ':' | LDEFAULT ':'
{ {
......
...@@ -702,6 +702,8 @@ opnames[] = ...@@ -702,6 +702,8 @@ opnames[] =
[OPANICN] = "PANICN", [OPANICN] = "PANICN",
[OPRINT] = "PRINT", [OPRINT] = "PRINT",
[OPRINTN] = "PRINTN", [OPRINTN] = "PRINTN",
[OPARAM] = "PARAM",
[ODCL] = "DCL",
[OXXX] = "XXX", [OXXX] = "XXX",
}; };
...@@ -877,6 +879,16 @@ Jconv(Fmt *fp) ...@@ -877,6 +879,16 @@ Jconv(Fmt *fp)
strncat(buf, buf1, sizeof(buf)); strncat(buf, buf1, sizeof(buf));
} }
if(n->class != 0) {
snprint(buf1, sizeof(buf1), " class(%d)", n->class);
strncat(buf, buf1, sizeof(buf));
}
if(n->colas != 0) {
snprint(buf1, sizeof(buf1), " colas(%d)", n->colas);
strncat(buf, buf1, sizeof(buf));
}
return fmtstrcpy(fp, buf); return fmtstrcpy(fp, buf);
} }
...@@ -2031,6 +2043,7 @@ ullmancalc(Node *n) ...@@ -2031,6 +2043,7 @@ ullmancalc(Node *n)
return; return;
switch(n->op) { switch(n->op) {
case OREGISTER:
case OLITERAL: case OLITERAL:
case ONAME: case ONAME:
ul = 1; ul = 1;
...@@ -2281,7 +2294,7 @@ Type** ...@@ -2281,7 +2294,7 @@ Type**
getthis(Type *t) getthis(Type *t)
{ {
if(t->etype != TFUNC) if(t->etype != TFUNC)
fatal("getthis: not a func %N", t); fatal("getthis: not a func %T", t);
return &t->type; return &t->type;
} }
...@@ -2289,7 +2302,7 @@ Type** ...@@ -2289,7 +2302,7 @@ Type**
getoutarg(Type *t) getoutarg(Type *t)
{ {
if(t->etype != TFUNC) if(t->etype != TFUNC)
fatal("getoutarg: not a func %N", t); fatal("getoutarg: not a func %T", t);
return &t->type->down; return &t->type->down;
} }
...@@ -2297,7 +2310,7 @@ Type** ...@@ -2297,7 +2310,7 @@ Type**
getinarg(Type *t) getinarg(Type *t)
{ {
if(t->etype != TFUNC) if(t->etype != TFUNC)
fatal("getinarg: not a func %N", t); fatal("getinarg: not a func %T", t);
return &t->type->down->down; return &t->type->down->down;
} }
......
...@@ -65,13 +65,20 @@ walk(Node *fn) ...@@ -65,13 +65,20 @@ walk(Node *fn)
if(curfn->type->outtuple) if(curfn->type->outtuple)
if(walkret(curfn->nbody)) if(walkret(curfn->nbody))
yyerror("function ends without a return statement"); yyerror("function ends without a return statement");
if(addtop != N) if(addtop != N) {
dump("addtop", addtop);
fatal("addtop in walk"); fatal("addtop in walk");
}
walkstate(curfn->nbody); walkstate(curfn->nbody);
if(debug['W']) { if(debug['W']) {
snprint(s, sizeof(s), "after %S", curfn->nname->sym); snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
dump(s, curfn->nbody); dump(s, curfn->nbody);
} }
heapmoves();
if(debug['W'] && curfn->enter != N) {
snprint(s, sizeof(s), "enter %S", curfn->nname->sym);
dump(s, curfn->enter);
}
} }
void void
...@@ -125,6 +132,7 @@ loop: ...@@ -125,6 +132,7 @@ loop:
case OCALLMETH: case OCALLMETH:
case OCALLINTER: case OCALLINTER:
case OCALL: case OCALL:
case ODCL:
case OSEND: case OSEND:
case ORECV: case ORECV:
case OPRINT: case OPRINT:
...@@ -229,6 +237,9 @@ loop: ...@@ -229,6 +237,9 @@ loop:
fatal("walktype: switch 1 unknown op %N", n); fatal("walktype: switch 1 unknown op %N", n);
goto ret; goto ret;
case ODCL:
goto ret;
case OLIST: case OLIST:
case OKEY: case OKEY:
walktype(n->left, top); walktype(n->left, top);
...@@ -283,7 +294,8 @@ loop: ...@@ -283,7 +294,8 @@ loop:
case ONAME: case ONAME:
if(top == Etop) if(top == Etop)
goto nottop; goto nottop;
n->addable = 1; if(!(n->class & PHEAP))
n->addable = 1;
if(n->type == T) { if(n->type == T) {
s = n->sym; s = n->sym;
if(s->undef == 0) { if(s->undef == 0) {
...@@ -681,7 +693,7 @@ loop: ...@@ -681,7 +693,7 @@ loop:
// structure literal // structure literal
if(t->etype == TSTRUCT) { if(t->etype == TSTRUCT) {
indir(n, structlit(n)); indir(n, structlit(n, nil));
goto ret; goto ret;
} }
...@@ -996,32 +1008,20 @@ loop: ...@@ -996,32 +1008,20 @@ loop:
// nvar := new(*Point); // nvar := new(*Point);
// *nvar = Point{1, 2}; // *nvar = Point{1, 2};
// and replace expression with nvar // and replace expression with nvar
Node *nvar, *nas;
// TODO(rsc): might do a better job (fewer copies) later nvar = nod(OXXX, N, N);
Node *nnew, *nvar, *nas; tempname(nvar, ptrto(n->left->type));
t = ptrto(n->left->type);
walktype(n->left, Elv);
if(n->left == N)
goto ret;
nvar = nod(0, N, N);
tempname(nvar, t);
nnew = nod(ONEW, N, N);
nnew->type = n->left->type;
nnew = newcompat(nnew);
nas = nod(OAS, nvar, nnew); nas = nod(OAS, nvar, callnew(n->left->type));
addtop = list(addtop, nas);
nas = nod(OAS, nod(OIND, nvar, N), n->left);
addtop = list(addtop, nas); addtop = list(addtop, nas);
structlit(n->left, nvar);
indir(n, nvar); indir(n, nvar);
goto ret; goto ret;
} }
walktype(n->left, Elv); walktype(n->left, Elv);
addrescapes(n->left);
if(n->left == N) if(n->left == N)
goto ret; goto ret;
t = n->left->type; t = n->left->type;
...@@ -1055,7 +1055,16 @@ loop: ...@@ -1055,7 +1055,16 @@ loop:
case ONEW: case ONEW:
if(top != Erv) if(top != Erv)
goto nottop; goto nottop;
indir(n, newcompat(n)); if(n->left != N) {
yyerror("cannot new(%T, expr)", t);
goto ret;
}
t = n->type;
if(t == T || t->etype == TFUNC) {
yyerror("cannot new(%T)", t);
goto ret;
}
indir(n, callnew(t));
goto ret; goto ret;
} }
...@@ -1455,8 +1464,8 @@ void ...@@ -1455,8 +1464,8 @@ void
walkselect(Node *sel) walkselect(Node *sel)
{ {
Iter iter; Iter iter;
Node *n, *oc, *on, *r; Node *n, *l, *oc, *on, *r;
Node *var, *bod, *res, *def; Node *var, *bod, *nbod, *res, *def;
int count, op; int count, op;
int32 lno; int32 lno;
...@@ -1492,6 +1501,7 @@ walkselect(Node *sel) ...@@ -1492,6 +1501,7 @@ walkselect(Node *sel)
def = n; def = n;
} else } else
op = n->left->op; op = n->left->op;
nbod = N;
switch(op) { switch(op) {
default: default:
yyerror("select cases must be send, recv or default"); yyerror("select cases must be send, recv or default");
...@@ -1499,14 +1509,32 @@ walkselect(Node *sel) ...@@ -1499,14 +1509,32 @@ walkselect(Node *sel)
case OAS: case OAS:
// convert new syntax (a=recv(chan)) to (recv(a,chan)) // convert new syntax (a=recv(chan)) to (recv(a,chan))
if(n->left->right == N || n->left->right->op != ORECV) { l = n->left;
if(l->right == N || l->right->op != ORECV) {
yyerror("select cases must be send, recv or default"); yyerror("select cases must be send, recv or default");
break; break;
} }
n->left->right->right = n->left->right->left; r = l->right; // rcv
n->left->right->left = n->left->left; r->right = r->left;
n->left = n->left->right; r->left = l->left;
n->left = r;
// convert case x := foo: body
// to case tmp := foo: x := tmp; body.
// if x escapes and must be allocated
// on the heap, this delays the allocation
// until after the select has chosen this branch.
if(n->ninit != N && n->ninit->op == ODCL) {
on = nod(OXXX, N, N);
tempname(on, l->left->type);
on->sym = lookup("!tmpselect!");
r->left = on;
nbod = nod(OAS, l->left, on);
nbod->ninit = n->ninit;
n->ninit = N;
}
// fall through
case OSEND: case OSEND:
case ORECV: case ORECV:
if(oc != N) { if(oc != N) {
...@@ -1516,10 +1544,8 @@ walkselect(Node *sel) ...@@ -1516,10 +1544,8 @@ walkselect(Node *sel)
oc = selcase(n, var); oc = selcase(n, var);
res = list(res, oc); res = list(res, oc);
break; break;
} }
bod = N; bod = nbod;
count++; count++;
break; break;
} }
...@@ -1610,6 +1636,7 @@ lookdot(Node *n, Type *t) ...@@ -1610,6 +1636,7 @@ lookdot(Node *n, Type *t)
switch(op) { switch(op) {
case OADDR: case OADDR:
walktype(n->left, Elv); walktype(n->left, Elv);
addrescapes(n->left);
n->left = nod(OADDR, n->left, N); n->left = nod(OADDR, n->left, N);
n->left->type = ptrto(tt); n->left->type = ptrto(tt);
break; break;
...@@ -1781,7 +1808,7 @@ sigtype(Type *st) ...@@ -1781,7 +1808,7 @@ sigtype(Type *st)
* match a ... parameter into an * match a ... parameter into an
* automatic structure. * automatic structure.
* then call the ... arg (interface) * then call the ... arg (interface)
* with a pointer to the structure * with a pointer to the structure.
*/ */
Node* Node*
mkdotargs(Node *r, Node *rr, Iter *saver, Node *nn, Type *l, int fp) mkdotargs(Node *r, Node *rr, Iter *saver, Node *nn, Type *l, int fp)
...@@ -1817,10 +1844,12 @@ mkdotargs(Node *r, Node *rr, Iter *saver, Node *nn, Type *l, int fp) ...@@ -1817,10 +1844,12 @@ mkdotargs(Node *r, Node *rr, Iter *saver, Node *nn, Type *l, int fp)
// make a named type for the struct // make a named type for the struct
st = sigtype(st); st = sigtype(st);
dowidth(st);
// now we have the size, make the struct // now we have the size, make the struct
var = nod(OXXX, N, N); var = nod(OXXX, N, N);
tempname(var, st); tempname(var, st);
var->sym = lookup(".ddd");
// assign the fields to the struct. // assign the fields to the struct.
// use addtop so that reorder1 doesn't reorder // use addtop so that reorder1 doesn't reorder
...@@ -1840,8 +1869,7 @@ mkdotargs(Node *r, Node *rr, Iter *saver, Node *nn, Type *l, int fp) ...@@ -1840,8 +1869,7 @@ mkdotargs(Node *r, Node *rr, Iter *saver, Node *nn, Type *l, int fp)
} }
// last thing is to put assignment // last thing is to put assignment
// of a pointer to the structure to // of the structure to the DDD parameter
// the DDD parameter
a = nod(OAS, nodarg(l, fp), var); a = nod(OAS, nodarg(l, fp), var);
nn = list(convas(a), nn); nn = list(convas(a), nn);
...@@ -2081,26 +2109,17 @@ makecompat(Node *n) ...@@ -2081,26 +2109,17 @@ makecompat(Node *n)
} }
Node* Node*
newcompat(Node *n) callnew(Type *t)
{ {
Node *r, *on; Node *r, *on;
Type *t;
t = n->type; dowidth(t);
if(t != T && t->etype != TFUNC) { on = syslook("mal", 1);
if(n->left != N) argtype(on, t);
yyerror("cannot new(%T, expr)", t); r = nodintconst(t->width);
dowidth(t); r = nod(OCALL, on, r);
on = syslook("mal", 1); walktype(r, Erv);
argtype(on, t); return r;
r = nodintconst(t->width);
r = nod(OCALL, on, r);
walktype(r, Erv);
return r;
}
yyerror("cannot new(%T)", t);
return n;
} }
Node* Node*
...@@ -2648,6 +2667,7 @@ arrayop(Node *n, int top) ...@@ -2648,6 +2667,7 @@ arrayop(Node *n, int top)
r = a; r = a;
a = nod(OADDR, n->left, N); // old a = nod(OADDR, n->left, N); // old
addrescapes(n->left);
r = list(a, r); r = list(a, r);
on = syslook("arrays2d", 1); on = syslook("arrays2d", 1);
...@@ -2671,6 +2691,7 @@ arrayop(Node *n, int top) ...@@ -2671,6 +2691,7 @@ arrayop(Node *n, int top)
r = a; r = a;
a = nod(OADDR, n->right, N); // old a = nod(OADDR, n->right, N); // old
addrescapes(n->right);
r = list(a, r); r = list(a, r);
on = syslook("arrays2d", 1); on = syslook("arrays2d", 1);
...@@ -3171,6 +3192,7 @@ ary: ...@@ -3171,6 +3192,7 @@ ary:
n->nbody = list(n->nbody, n->nbody = list(n->nbody,
nod(OAS, v, nod(OINDEX, m, hk)) ); nod(OAS, v, nod(OINDEX, m, hk)) );
} }
addtotop(n);
goto out; goto out;
map: map:
...@@ -3457,18 +3479,20 @@ reorder4(Node *n) ...@@ -3457,18 +3479,20 @@ reorder4(Node *n)
} }
Node* Node*
structlit(Node *n) structlit(Node *n, Node *var)
{ {
Iter savel, saver; Iter savel, saver;
Type *l, *t; Type *l, *t;
Node *var, *r, *a; Node *r, *a;
t = n->type; t = n->type;
if(t->etype != TSTRUCT) if(t->etype != TSTRUCT)
fatal("structlit: not struct"); fatal("structlit: not struct");
var = nod(OXXX, N, N); if(var == N) {
tempname(var, t); var = nod(OXXX, N, N);
tempname(var, t);
}
l = structfirst(&savel, &n->type); l = structfirst(&savel, &n->type);
r = listfirst(&saver, &n->left); r = listfirst(&saver, &n->left);
...@@ -3488,6 +3512,7 @@ loop: ...@@ -3488,6 +3512,7 @@ loop:
a = nod(ODOT, var, newname(l->sym)); a = nod(ODOT, var, newname(l->sym));
a = nod(OAS, a, r); a = nod(OAS, a, r);
walktype(a, Etop); // add any assignments in r to addtop
addtop = list(addtop, a); addtop = list(addtop, a);
l = structnext(&savel); l = structnext(&savel);
...@@ -3605,3 +3630,115 @@ loop: ...@@ -3605,3 +3630,115 @@ loop:
r = listnext(&saver); r = listnext(&saver);
goto loop; goto loop;
} }
/*
* the address of n has been taken and might be used after
* the current function returns. mark any local vars
* as needing to move to the heap.
*/
static char *pnames[] = {
[PAUTO] "auto",
[PPARAM] "param",
[PPARAMOUT] "param_out",
};
void
addrescapes(Node *n)
{
char buf[100];
switch(n->op) {
default:
dump("addrescapes", n);
break;
case ONAME:
if(n->noescape)
break;
switch(n->class) {
case PPARAMOUT:
yyerror("cannot take address of out parameter %s", n->sym->name);
break;
case PAUTO:
case PPARAM:
if(debug['E'])
print("%L %s %S escapes %p\n", n->lineno, pnames[n->class], n->sym, n);
n->class |= PHEAP;
n->addable = 0;
n->ullman = 2;
n->alloc = callnew(n->type);
// if func param, need separate temporary
// to hold heap pointer.
if(n->class == PPARAM+PHEAP) {
// expression to refer to stack copy
n->stackparam = nod(OPARAM, n, N);
n->stackparam->type = n->type;
n->stackparam->addable = 1;
n->stackparam->xoffset = n->xoffset;
n->xoffset = 0;
}
// create stack variable to hold pointer to heap
n->heapaddr = nod(0, N, N);
tempname(n->heapaddr, ptrto(n->type));
snprint(buf, sizeof buf, "&%S", n->sym);
n->heapaddr->sym = lookup(buf);
break;
}
break;
case OIND:
case ODOTPTR:
break;
case ODOT:
case OINDEX:
// ODOTPTR has already been
// introduced, so these are the non-pointer
// ODOT and OINDEX.
addrescapes(n->left);
break;
}
}
/*
* walk through argin parameters.
* generate and return code to allocate
* copies of escaped parameters to the heap.
*/
Node*
paramstoheap(Type **argin)
{
Type *t;
Iter savet;
Node *v, *nn;
nn = N;
for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
if(t->sym == S)
continue;
v = t->sym->oname;
if(v == N || !(v->class & PHEAP))
continue;
// generate allocation & copying code
nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
nn = list(nn, nod(OAS, v, v->stackparam));
}
return nn;
}
/*
* take care of migrating any function in/out args
* between the stack and the heap. adds code to
* curfn's before and after lists.
*/
void
heapmoves(void)
{
Node *nn;
nn = paramstoheap(getthis(curfn->type));
nn = list(nn, paramstoheap(getinarg(curfn->type)));
curfn->enter = list(curfn->enter, nn);
}
...@@ -237,8 +237,14 @@ sys·printpointer(void *p) ...@@ -237,8 +237,14 @@ sys·printpointer(void *p)
void void
sys·printstring(string v) sys·printstring(string v)
{ {
if(v != nil) extern int32 maxstring;
sys·write(1, v->str, v->len);
if(v != nil) {
if(v->len > maxstring)
sys·write(1, "[invalid string]", 16);
else
sys·write(1, v->str, v->len);
}
} }
void void
......
...@@ -17,6 +17,20 @@ findnull(byte *s) ...@@ -17,6 +17,20 @@ findnull(byte *s)
return l; return l;
} }
int32 maxstring;
string
gostringsize(int32 l)
{
string s;
s = mal(sizeof(s->len)+l+1);
s->len = l;
if(l > maxstring)
maxstring = l;
return s;
}
string string
gostring(byte *str) gostring(byte *str)
{ {
...@@ -24,8 +38,7 @@ gostring(byte *str) ...@@ -24,8 +38,7 @@ gostring(byte *str)
string s; string s;
l = findnull(str); l = findnull(str);
s = mal(sizeof(s->len)+l+1); s = gostringsize(l);
s->len = l;
mcpy(s->str, str, l+1); mcpy(s->str, str, l+1);
return s; return s;
} }
...@@ -46,8 +59,7 @@ sys·catstring(string s1, string s2, string s3) ...@@ -46,8 +59,7 @@ sys·catstring(string s1, string s2, string s3)
l = s1->len + s2->len; l = s1->len + s2->len;
s3 = mal(sizeof(s3->len)+l); s3 = gostringsize(l);
s3->len = l;
mcpy(s3->str, s1->str, s1->len); mcpy(s3->str, s1->str, s1->len);
mcpy(s3->str+s1->len, s2->str, s2->len); mcpy(s3->str+s1->len, s2->str, s2->len);
...@@ -139,8 +151,7 @@ sys·slicestring(string si, int32 lindex, int32 hindex, string so) ...@@ -139,8 +151,7 @@ sys·slicestring(string si, int32 lindex, int32 hindex, string so)
} }
l = hindex-lindex; l = hindex-lindex;
so = mal(sizeof(so->len)+l); so = gostringsize(l);
so->len = l;
mcpy(so->str, si->str+lindex, l); mcpy(so->str, si->str+lindex, l);
FLUSH(&so); FLUSH(&so);
} }
...@@ -164,7 +175,7 @@ sys·indexstring(string s, int32 i, byte b) ...@@ -164,7 +175,7 @@ sys·indexstring(string s, int32 i, byte b)
void void
sys·intstring(int64 v, string s) sys·intstring(int64 v, string s)
{ {
s = mal(sizeof(s->len)+8); s = gostringsize(8);
s->len = runetochar(s->str, v); s->len = runetochar(s->str, v);
FLUSH(&s); FLUSH(&s);
} }
...@@ -172,8 +183,7 @@ sys·intstring(int64 v, string s) ...@@ -172,8 +183,7 @@ sys·intstring(int64 v, string s)
void void
sys·byteastring(byte *a, int32 l, string s) sys·byteastring(byte *a, int32 l, string s)
{ {
s = mal(sizeof(s->len)+l); s = gostringsize(l);
s->len = l;
mcpy(s->str, a, l); mcpy(s->str, a, l);
FLUSH(&s); FLUSH(&s);
} }
...@@ -181,8 +191,7 @@ sys·byteastring(byte *a, int32 l, string s) ...@@ -181,8 +191,7 @@ sys·byteastring(byte *a, int32 l, string s)
void void
sys·arraystring(Array b, string s) sys·arraystring(Array b, string s)
{ {
s = mal(sizeof(s->len)+b.nel); s = gostringsize(b.nel);
s->len = b.nel;
mcpy(s->str, b.array, s->len); mcpy(s->str, b.array, s->len);
FLUSH(&s); FLUSH(&s);
} }
// $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2009 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
// check for correct heap-moving of escaped variables.
// it is hard to check for the allocations, but it is easy
// to check that if you call the function twice at the
// same stack level, the pointers returned should be
// different.
var bad = false
var allptr = make([]*int, 0, 100);
func noalias(p, q *int, s string) {
n := len(allptr);
*p = -(n+1);
*q = -(n+2);
allptr = allptr[0:n+2];
allptr[n] = p;
allptr[n+1] = q;
n += 2;
for i := 0; i < n; i++ {
if allptr[i] != nil && *allptr[i] != -(i+1) {
println("aliased pointers", -(i+1), *allptr[i], "after", s);
allptr[i] = nil;
bad = true;
}
}
}
func val(p, q *int, v int, s string) {
if *p != v {
println("wrong value want", v, "got", *p, "after", s);
bad = true;
}
if *q != v+1 {
println("wrong value want", v+1, "got", *q, "after", s);
bad = true;
}
}
func chk(p, q *int, v int, s string) {
val(p, q, v, s);
noalias(p, q, s);
}
func chkalias(p, q *int, v int, s string) {
if p != q {
println("want aliased pointers but got different after", s);
}
if *q != v+1 {
println("wrong value want", v+1, "got", *q, "after", s);
}
}
func i_escapes(x int) *int {
var i int;
i = x;
return &i;
}
func j_escapes(x int) *int {
var j int = x;
j = x;
return &j;
}
func k_escapes(x int) *int {
k := x;
return &k;
}
func in_escapes(x int) *int {
return &x;
}
func send(c chan int, x int) {
c <- x;
}
func select_escapes(x int) *int {
c := make(chan int);
go send(c, x);
select {
case req := <-c:
return &req;
}
return nil;
}
func select_escapes1(x int, y int) (*int, *int) {
c := make(chan int);
var a [2]int;
var p [2]*int;
a[0] = x;
a[1] = y;
for i := 0; i < 2; i++ {
go send(c, a[i]);
select {
case req := <-c:
p[i] = &req;
}
}
return p[0], p[1]
}
func range_escapes(x int) *int {
var a [1]int;
a[0] = x;
for k, v := range a {
return &v;
}
return nil;
}
// *is* aliased
func range_escapes2(x, y int) (*int, *int) {
var a [2]int;
var p [2]*int;
a[0] = x;
a[1] = y;
for k, v := range a {
p[k] = &v;
}
return p[0], p[1]
}
// *is* aliased
func for_escapes2(x int, y int) (*int, *int) {
var p [2]*int;
n := 0;
for i := x; n < 2; i = y {
p[n] = &i;
n++;
}
return p[0], p[1]
}
func main() {
p, q := i_escapes(1), i_escapes(2);
chk(p, q, 1, "i_escapes");
p, q = j_escapes(3), j_escapes(4);
chk(p, q, 3, "j_escapes");
p, q = k_escapes(5), k_escapes(6);
chk(p, q, 5, "k_escapes");
p, q = in_escapes(7), in_escapes(8);
chk(p, q, 7, "in_escapes");
p, q = select_escapes(9), select_escapes(10);
chk(p, q, 9, "select_escapes");
p, q = select_escapes1(11, 12);
chk(p, q, 11, "select_escapes1");
p, q = range_escapes(13), range_escapes(14);
chk(p, q, 13, "range_escapes");
p, q = range_escapes2(101, 102);
chkalias(p, q, 101, "range_escapes2");
p, q = for_escapes2(103, 104);
chkalias(p, q, 103, "for_escapes2");
if bad {
panic("BUG: no escape");
}
}
// errchk $G $D/$F.go
// Copyright 2009 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
func out_escapes() (x int, p *int) {
p = &x; // ERROR "address.*out parameter"
return;
}
func out_escapes() (x int, p *int) {
return 2, &x; // ERROR "address.*out parameter"
}
...@@ -172,7 +172,7 @@ bugs/bug129.go:6: syscall is package, not var ...@@ -172,7 +172,7 @@ bugs/bug129.go:6: syscall is package, not var
BUG129 BUG129
=========== bugs/bug130.go =========== bugs/bug130.go
bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE bugs/bug130.go:14: fatal error: getoutarg: not a func *<T>
BUG: should run BUG: should run
=========== bugs/bug131.go =========== bugs/bug131.go
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment